|
|
1.1 root 1: # include <ingres.h>
2: # include <aux.h>
3: # include <tree.h>
4: # include <symbol.h>
5: # include <sccs.h>
6:
7: SCCSID(@(#)norml.c 8.1 12/31/84)
8:
9: extern QTREE *treedup();
10: extern char *need();
11:
12:
13: /*
14: ** NORML
15: ** this routine passes the qualification clause portion of the query
16: ** tree to the routines for depressing nots and for conjunctive
17: ** normalization. It also calls a routine to place an and with one
18: ** null branch at the rightmost end of the tree.
19: */
20:
21: QTREE *
22: norml(ptr)
23: QTREE *ptr;
24: {
25: extern QTREE *nnorm();
26: extern QTREE *travers();
27: extern QTREE *tree();
28:
29: # ifdef xQTR2
30: if (tTf(73, 0))
31: treepr(ptr, "->NORML");
32: # endif
33:
34: if (ptr == NULL)
35: return (tree(NULL, NULL, QLEND, 0, 0));
36:
37: /* push through the 'nots' as far a possible */
38: ptr = nnorm(ptr);
39:
40: /* make tree into conjunctive normal form */
41: ptr = travers(ptr);
42:
43: /* terminate the list on the rightmost branch */
44: adjust(&ptr);
45:
46: # ifdef xQTR3
47: if (tTf(73, 2))
48: treepr(ptr, "before mvands");
49: # endif
50:
51: /* make 'ands' into a linear list */
52: mvands(ptr);
53:
54: # ifdef xQTR2
55: if (tTf(73, 1))
56: treepr(ptr, "<-NORML");
57: # endif
58:
59: return (ptr);
60: }
61:
62:
63: /*
64: ** NORM
65: ** this routine takes a tree which has nots only at the lower ends, and
66: ** places it into conjunctive normal form by repeatedly applying the
67: ** replacement rule: A or (B and C) ==> (A or B) and (A or C)
68: */
69: QTREE *
70: norm(p1)
71: QTREE *p1;
72: {
73: extern QTREE *tree();
74: register QTREE *p;
75: register QTREE *lptr;
76: register QTREE *rptr;
77:
78: p = p1;
79: switch (p->sym.type)
80: {
81: case AND:
82: p->left = norm(p->left);
83: p->right = norm(p->right);
84: break;
85:
86: case OR:
87: if (p->right->sym.type == AND)
88: {
89: andright:
90: /*
91: ** combine left subtree with each subtree of the
92: ** right subtree
93: */
94: /*
95: ** use copy first so that the copy is guaranteed to be
96: ** the same as the original
97: */
98: lptr = tree(treedup(p->left), p->right->left, OR, 0, 0);
99: rptr = tree(p->left, p->right->right, OR, 0, 0);
100: lptr = norm(lptr);
101: rptr = norm(rptr);
102: /* change node type to AND from OR */
103: p->left = lptr;
104: p->right = rptr;
105: p->sym.type = AND; /* length is same */
106: break;
107: }
108: if (p->left->sym.type == AND)
109: {
110: andleft:
111: /*
112: ** combine right subtree with each subtree of the
113: ** left subtree
114: */
115: /*
116: ** again, the copy should be used first
117: */
118: lptr = tree(p->left->left, treedup(p->right), OR, 0, 0);
119: rptr = tree(p->left->right, p->right, OR, 0, 0);
120: lptr = norm(lptr);
121: rptr = norm(rptr);
122: /* change node type to AND from OR */
123: p->left = lptr;
124: p->right = rptr;
125: p->sym.type = AND;
126: break;
127: }
128: /*
129: ** when TRAVERS is being used to optomize the normalization
130: ** order there should never be (I think) an OR as a child
131: ** of the OR in the parent. Since TRAVERS works bottom up
132: ** in the tree the second OR level should be gone.
133: */
134: if (p->right->sym.type == OR)
135: {
136: /* skip this (p->sym.type) "or" and normalize the right subtree */
137: p->right = norm(p->right);
138:
139: /* now re-try the current node */
140: if (p->right->sym.type == AND)
141: goto andright;
142: break;
143: }
144: if (p->left->sym.type == OR)
145: {
146: /* skip this "or" and normalize the left subtree */
147: p->left = norm(p->left);
148:
149: /* now re-try the current node */
150: if (p->left->sym.type == AND)
151: goto andleft;
152: break;
153: }
154: break;
155: }
156: return (p);
157: }
158:
159: /*
160: ** TRAVERS
161: ** traverse the tree so that conversion of ORs of ANDs can
162: ** take place at the innermost clauses first. IE, normalize
163: ** before replication rather than after replication.
164: **
165: ** This routine need not be used. The NORM routine will completely
166: ** traverse the tree and normalize it but... TRAVERS finds
167: ** the lowest subtree to normalize first so that sub-trees can
168: ** be normalized before replication, hence reducing the time required
169: ** to normalize large trees. It will also make OR-less trees faster
170: ** to normalize (since nothing need be done to it).
171: */
172: QTREE *
173: travers(p1)
174: QTREE *p1;
175: {
176: register QTREE *p;
177: extern QTREE *norm();
178:
179: p = p1;
180: if (p->right != NULL)
181: p->right = travers(p->right);
182: if (p->left != NULL)
183: p->left = travers(p->left);
184: if (p->sym.type == OR)
185: p = norm(p);
186: return (p);
187: }
188: /*
189: ** NNORM
190: ** this routine depresses nots in the query tree to the lowest possible
191: ** nodes. It may also affect arithmetic operators in this procedure
192: */
193: QTREE *
194: nnorm(p1)
195: QTREE *p1;
196: {
197: extern QTREE *notpush();
198: register QTREE *p;
199:
200: p = p1;
201: if (p->sym.type == AGHEAD)
202: {
203: /*
204: ** don't need to continue past an AGHEAD
205: ** actually, it causes problems if you do
206: ** because the qualification on the agg
207: ** has already been normalized and the
208: ** QLEND needs to stay put
209: */
210: return (p);
211: }
212: if ((p->sym.type == UOP) && (p->sym.value.sym_op.opno == opNOT))
213: {
214: /* skip not node */
215: p = p->right;
216: p = notpush(p);
217: }
218: else
219: {
220: if (p->left != NULL)
221: p->left = nnorm(p->left);
222: if (p->right != NULL)
223: p->right = nnorm(p->right);
224: }
225: return (p);
226: }
227:
228: /*
229: ** NOTPUSH
230: ** this routine decides what to do once a not has been found in the
231: ** query tree
232: */
233: QTREE *
234: notpush(p1)
235: QTREE *p1;
236: {
237: extern QTREE *nnorm();
238: register QTREE *p;
239:
240: p = p1;
241: switch (p->sym.type)
242: {
243: case AND:
244: p->sym.type = OR;
245: p->left = notpush(p->left);
246: p->right = notpush(p->right);
247: break;
248:
249: case OR:
250: p->sym.type = AND;
251: p->left = notpush(p->left);
252: p->right = notpush(p->right);
253: break;
254:
255: case BOP:
256: switch (p->sym.value.sym_op.opno)
257: {
258: case opEQ:
259: p->sym.value.sym_op.opno = opNE;
260: break;
261:
262: case opNE:
263: p->sym.value.sym_op.opno = opEQ;
264: break;
265:
266: case opLT:
267: p->sym.value.sym_op.opno = opGE;
268: break;
269:
270: case opGE:
271: p->sym.value.sym_op.opno = opLT;
272: break;
273:
274: case opLE:
275: p->sym.value.sym_op.opno = opGT;
276: break;
277:
278: case opGT:
279: p->sym.value.sym_op.opno = opLE;
280: break;
281:
282: default:
283: syserr("strange BOP in notpush '%d'", p->sym.value.sym_op.opno);
284: }
285: break;
286:
287: case UOP:
288: if (p->sym.value.sym_op.opno == opNOT)
289: {
290: /* skip not node */
291: p = p->right;
292: p = nnorm(p);
293: }
294: else
295: syserr("strange UOP in notpush '%d'", p->sym.value.sym_op.opno);
296: break;
297:
298: default:
299: syserr("unrecognizable node type in notpush '%d'", p->sym.type);
300: }
301: return (p);
302: }
303:
304: /*
305: ** ADJUST
306: ** terminate qual with an AND and a QLEND at the rightmost branch
307: */
308: adjust(pp)
309: QTREE **pp;
310: {
311: extern QTREE *tree();
312: register QTREE *p;
313:
314: p = *pp;
315: switch (p->sym.type)
316: {
317: case AND:
318: adjust(&(p->right));
319: break;
320:
321: case OR:
322: default:
323: *pp = tree(p, tree(NULL, NULL, QLEND, 0, NULL), AND, 0, 0);
324: break;
325: }
326: }
327:
328: QTREE *
329: treedup(p)
330: register QTREE *p;
331: {
332: register QTREE *np;
333: extern char Qbuf[];
334:
335: if (p == NULL)
336: return (p);
337: np = (QTREE *) need(Qbuf, (p->sym.len & I1MASK) + QT_HDR_SIZ);
338: bmove(p, np, (p->sym.len & I1MASK) + QT_HDR_SIZ);
339: np->left = treedup(p->left);
340: np->right = treedup(p->right);
341: return (np);
342: }
343:
344: /*
345: ** MVANDS -- pushes all AND's in Qual into linear list
346: */
347: mvands(andp)
348: QTREE *andp;
349: {
350: register QTREE *ap, *lp, *rp;
351:
352: ap = andp;
353: if (ap->sym.type == QLEND)
354: return;
355: rp = ap->right;
356: lp = ap->left;
357: if (lp->sym.type == AND)
358: {
359: ap->left = lp->right;
360: ap->right = lp;
361: lp->right = rp;
362: mvands(ap);
363: }
364: else
365: mvands(rp);
366: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.