|
|
1.1 root 1: # include <ingres.h>
2: # include <tree.h>
3: # include <symbol.h>
4: # include "globs.h"
5: # include <sccs.h>
6: # include <errors.h>
7:
8: SCCSID(@(#)aggregate.c 8.3 2/8/85)
9:
10:
11:
12:
13: /*
14: ** AGGREGATE - replace aggregates with their values
15: **
16: ** Aggregate attempts to optimize aggregate processing
17: ** wherever possible. It replaces aggregates with their
18: ** values, and links aggregate functions which have
19: ** identical by-lists together.
20: **
21: ** Note that for the sake of this code, A "prime"
22: ** aggregate is one in which duplicates are removed.
23: ** These are COUNTU, SUMU, and AVGU.
24: **
25: ** Aggregate first forms a list of all aggregates in
26: ** the order they should be processed.
27: **
28: ** For each aggregate, it looks at all other aggregates
29: ** to see if there are two simple aggregates
30: ** or if there is another aggregate funtion with the
31: ** same by-list.
32: **
33: ** An attempt is made to run
34: ** as many aggregates as possible at once. This can be
35: ** done only if two or more aggregates have the same
36: ** qualifications and in the case of aggregate functions,
37: ** they must have identical by-lists.
38: ** Even then, certain combinations
39: ** of aggregates cannot occure together. The list is
40: ** itemized later in the code.
41: **
42: ** Aggregate calls BYEVAL or AGEVAL to actually process
43: ** aggregate functions or aggregates respectively.
44: **
45: ** Trace Flags:
46: ** 40
47: */
48:
49: aggregate(root)
50: QTREE *root;
51: {
52: struct agglist alist[MAXAGG + 1];
53: QTREE *rlist[MAXAGG + 1];
54: struct agglist *al, *al1;
55: register QTREE *agg, *aop1, *r;
56: QTREE *aop, *agg1;
57: int i, simple_agg, varmap;
58: int attcnt, anyagg, attoff, twidth;
59: QTREE *makavar(), *agspace();
60: extern char *rangename();
61: extern QTREE *ageval();
62: extern QTREE *byeval();
63:
64: al = alist;
65: De.de_aggnext = al;
66: De.de_agglim = &al[MAXAGG];
67:
68: findagg(&root, root); /* generate list of all aggregates */
69: De.de_aggnext->agpoint = 0; /* mark end of the list */
70: anyagg = 0;
71:
72: varmap = root->sym.value.sym_root.lvarm | root->sym.value.sym_root.rvarm;
73:
74: /* process each aggregate */
75: for (;agg = al->agpoint; al++)
76: {
77: /* is this still an aggregate? */
78: if (agg->sym.type != AGHEAD)
79: continue;
80: mapvar(agg, 0); /* map the aggregate tree */
81: anyagg++;
82:
83: De.de_sourcevar = bitpos(agg->sym.value.sym_root.lvarm | agg->sym.value.sym_root.rvarm);
84: # ifdef xDTR1
85: if (tTf(40, 4))
86: printf("De.de_sourcevar=%d,rel=%s\n", De.de_sourcevar, rangename(De.de_sourcevar));
87: # endif
88:
89: simple_agg = (agg->left->sym.type == AOP); /* TRUE if no bylist */
90: aop = agg->left; /* assume it was TRUE */
91: # ifdef xDTR1
92: if (tTf(40, 0))
93: printf("%s\n", simple_agg ? "agg" : "agg-func");
94: # endif
95: if (simple_agg)
96: {
97: /* simple aggregate */
98: rlist[0] = agspace(aop);
99: twidth = aop->sym.value.sym_op.opfrml & I1MASK; /* init width to the width of the aggregate */
100: }
101: else
102: {
103: attoff = agg->left->left->sym.value.sym_resdom.resno + 2;
104: aop = aop->right; /* find the AOP node */
105: /* assign new source variable for aggregate */
106: al->agvarno = getrange(&varmap);
107: /* compute width of bylist + count field */
108: twidth = findwid(agg->left) + 4;
109:
110: /* make sure the aggregate does not exceed max dimensions */
111: if (chkwidth(aop, &twidth, attoff))
112: derror(AGFTOBIG);
113: }
114: attcnt = 1; /* one aggregate so far */
115:
116: /* look for another identical aggregate */
117: for (al1 = al + 1; agg1 = al1->agpoint; al1++)
118: {
119:
120: /* if agg is nested inside agg1 then ignore it */
121: if (al->agfather == agg1 || agg1->sym.type != AGHEAD)
122: {
123: continue;
124: }
125:
126: /* split aggs and agg-func apart */
127: /* check for identical aggregate */
128: if (simple_agg)
129: {
130: aop1 = agg1->left; /* find AOP node */
131:
132: if (aop1->sym.type != AOP)
133: continue; /* not a simple agg */
134:
135: /* make sure they can be run together */
136: if (checkagg(agg, aop, agg1, aop1) == 0)
137: continue;
138:
139: if ((i = sameagg(agg, aop1, attcnt)) >= 0)
140: {
141: /* found identical aggregate to rlist[i] */
142: r = rlist[i];
143: }
144: else
145: {
146: /* put this agg in with the others */
147:
148: /* first make sure it won't exceed tuple length */
149: if (chkwidth(aop1, &twidth, 0))
150: continue; /* can't be included */
151: r = rlist[attcnt++] = agspace(aop1);
152:
153: /* connect into tree */
154: aop1->left = agg->left;
155: agg->left = aop1;
156: }
157: }
158: else
159: {
160: /* aggregate function */
161: if (!sameafcn(agg->left->left, agg1->left->left))
162: continue;
163:
164: aop1 = agg1->left->right; /* find AOP */
165:
166:
167: if (checkagg(agg, aop, agg1, aop1) == 0)
168: {
169: /* same by-lists but they can't be run together */
170: continue;
171: }
172:
173: if ((i = sameagg(agg, aop1, attcnt)) < 0)
174: {
175: /* make sure there is room */
176: if (chkwidth(aop1, &twidth, attcnt + attoff))
177: continue;
178:
179: /* add aggregate into tree */
180: i = attcnt++;
181:
182: aop1->left = agg->left->right;
183: agg->left->right = aop1;
184: }
185:
186: r = makavar(aop1, al->agvarno, i + attoff);
187: }
188: /* replace aggregate in original tree with its value */
189: *(al1->father) = r;
190:
191: /* remove aggregate from local list */
192: agg1->sym.type = -1;
193: # ifdef xDTR1
194: if (tTf(40, 3))
195: printf("including aghead %x\n", agg1);
196: # endif
197: }
198:
199: /* process aggregate */
200: if (simple_agg)
201: {
202: rlist[attcnt] = 0;
203: ageval(agg, rlist); /* pass tree and result list */
204: r = rlist[0];
205: }
206: else
207: {
208: opt_bylist(alist, agg);
209: byeval(al->agfather, agg, al->agvarno);
210: r = makavar(aop, al->agvarno, attoff);
211: }
212: /*
213: ** Link result into tree. al->father hold the address
214: ** &(tree->left) or &(tree->right).
215: */
216: *(al->father) = r;
217: # ifdef xDTR1
218: if (tTf(40, 4))
219: {
220: printf("agg value\n");
221: treepr(*(al->father));
222: }
223: # endif
224: }
225: if (anyagg)
226: {
227: opt_bylist(alist, root);
228: mapvar(root, 0); /* remap main tree */
229: }
230: }
231: /*
232: ** findagg builds a list of all aggregates
233: ** in the tree. It finds them by leftmost
234: ** innermost first.
235: **
236: ** The parameters represent:
237: ** nodep: the address of the node pointing to you
238: ** eg. &(tree->left) or &(tree->right)
239: ** agf: the root node. or if we are inside
240: ** a nested aggregate, the AGHEAD node
241: */
242:
243: findagg(nodep, agf)
244: QTREE **nodep;
245: QTREE *agf;
246: {
247: register QTREE *q, *f;
248: register struct agglist *list;
249: int agg;
250:
251: if ((q = *nodep) == NULL)
252: return;
253:
254: f = agf;
255: if (agg = (q->sym.type == AGHEAD))
256: f = q; /* this aggregate is now the father root */
257:
258: /* find all aggregates below */
259: findagg(&(q->left), f);
260: findagg(&(q->right), f);
261:
262: /* if this is an aggregate, put it on the list */
263: if (agg)
264: {
265: if (De.de_aggnext >= De.de_agglim)
266: derror(TOOMANYAGGS);
267: list = De.de_aggnext;
268: list->father = nodep;
269: list->agpoint = q;
270: list->agfather = agf;
271: De.de_aggnext++;
272: }
273: }
274: /*
275: ** Agspace allocates space for the result of
276: ** a simple aggregate.
277: */
278:
279: QTREE *
280: agspace(aop)
281: QTREE *aop;
282: {
283: register QTREE *a, *r;
284: register int length;
285: extern char *need();
286:
287: a = aop;
288: length = a->sym.value.sym_op.opfrml & I1MASK;
289: r = (QTREE *) need(De.de_qbuf, length + QT_HDR_SIZ);
290: r->left = r->right = 0;
291: r->sym.type = a->sym.value.sym_op.opfrmt;
292: r->sym.len = length;
293:
294: return (r);
295: }
296: /*
297: ** Chkwidth -- make sure that the inclusion of another aggregate will
298: ** not exceed the system limit. This means that the total width
299: ** cannot exceed MAXTUP and the number of domains cannot exceed MAXDOM-1
300: */
301:
302: chkwidth(aop, widthp, domno)
303: QTREE *aop;
304: int *widthp;
305: int domno;
306: {
307: register int width;
308:
309: width = *widthp;
310:
311: # ifdef xDTR1
312: if (tTf(40, 10))
313: printf("agg width %d,dom %d\n", width, domno);
314: # endif
315:
316: width += (aop->sym.value.sym_op.opfrml & I1MASK);
317:
318: if (width > MAXTUP || domno > MAXDOM - 1)
319: return (1);
320:
321: *widthp = width;
322: return (0);
323: }
324: /*
325: ** Determine whether an aggregate is prime
326: ** or a don't care aggregate. Returns TRUE
327: ** if COUNTU,SUMU,AVGU,MIN,MAX,ANY.
328: ** Returns false if COUNT,SUM,AVG.
329: */
330:
331: cprime(aop)
332: QTREE *aop;
333: {
334: register int i;
335:
336: i = TRUE;
337: switch (aop->sym.value.sym_op.opno)
338: {
339: case opCOUNT:
340: case opSUM:
341: case opAVG:
342: i = FALSE;
343: }
344: return (i);
345: }
346: /*
347: ** Getrange find a free slot in the range table
348: ** for an aggregate function.
349: **
350: ** If there are no free slots,derror is called
351: */
352:
353: getrange(varmap)
354: int *varmap;
355: {
356: register int i, map, bit;
357:
358: map = *varmap;
359:
360: for (i = 0; i < MAXRANGE; i++)
361: {
362: /* if slot is used, continue */
363: if ((bit = 1 << i) & map)
364: continue;
365:
366: map |= bit; /* "or" bit into the map */
367: *varmap = map;
368:
369: # ifdef xDTR1
370: if (tTf(40, 10))
371: printf("Assn var %d, map %o\n", i, map);
372: # endif
373:
374: return (i);
375: }
376: derror(NODESCAG);
377: return (-1);
378: }
379:
380:
381: checkagg(aghead1, aop1, aghead2, aop2)
382: QTREE *aghead1;
383: QTREE *aop1;
384: QTREE *aghead2;
385: QTREE *aop2;
386: {
387: register QTREE *aop_1, *aop_2, *agg1;
388: int ok;
389:
390: /* two aggregate functions can be run together
391: ** according to the following table:
392: **
393: ** prime !prime don't care
394: **
395: ** prime afcn? never afcn?
396: ** !prime never always always
397: ** don't care afcn? always always
398: **
399: ** don't care includes: ANY, MIN, MAX
400: ** afcn? means only if a-fcn's are identical
401: */
402:
403: aop_1 = aop1;
404: aop_2 = aop2;
405: agg1 = aghead1;
406:
407: if (!prime(aop_1) && !prime(aop_2))
408: ok = TRUE;
409: else
410: if (sameafcn(aop_1->right, aop_2->right))
411: ok = cprime(aop_1) && cprime(aop_2);
412: else
413: ok = FALSE;
414: /* The two aggregates must range over the same variables */
415: if ((agg1->sym.value.sym_root.lvarm | agg1->sym.value.sym_root.rvarm) != (aghead2->sym.value.sym_root.lvarm | aghead2->sym.value.sym_root.rvarm))
416: ok = FALSE;
417:
418:
419: /* check the qualifications */
420: if (ok)
421: ok = sameafcn(agg1->right, aghead2->right);
422: return (ok);
423: }
424:
425:
426: sameagg(aghead, newaop, agg_depth)
427: QTREE *aghead;
428: QTREE *newaop;
429: int agg_depth;
430: {
431: register QTREE *agg, *newa;
432: register int i;
433:
434: agg = aghead;
435: newa = newaop;
436: agg = agg->left;
437: if (agg->sym.type == BYHEAD)
438: agg = agg->right;
439:
440: /* agg now points to first aggregate */
441: for (i = 1; agg; agg = agg->left, i++)
442: if (sameafcn(agg->right, newa->right) && agg->sym.value.sym_resdom.resno == newa->sym.value.sym_op.opno)
443: {
444: # ifdef xDTR1
445: if (tTf(40, 6))
446: printf("found identical aop %x\n", newa);
447: # endif
448: return (agg_depth - i);
449: }
450:
451: /* no match */
452: return (-1);
453: }
454:
455:
456:
457:
458: opt_bylist(alist, root)
459: struct agglist *alist;
460: QTREE *root;
461: {
462: register struct agglist *al;
463: register QTREE *agg;
464: register struct hitlist *hl;
465: QTREE **tpr, *tree, *lnodv[MAXDOM+2];
466: struct hitlist hlist[30];
467: int anyop, i, usedmap, vars, treemap;
468:
469: /* compute bitmap of all possible vars in tree (can include xtra vars) */
470: treemap = root->sym.value.sym_root.lvarm | root->sym.value.sym_root.rvarm;
471: anyop = FALSE;
472:
473: /* scan the list of aggregates looking for one nested in root */
474: for (al = alist; (agg = al->agpoint) && agg != root; al++)
475: {
476: if (agg->sym.type == AGHEAD && agg->left->sym.type == BYHEAD &&
477: al->agfather == root)
478: {
479:
480: /* this aggregate function is nested in root */
481:
482: /* make sure it has some vars of interest */
483: if ((treemap & varfind(agg->left->left, (QTREE *)NULL)) == 0)
484: continue;
485:
486: # ifdef xDTR1
487: if (tTf(40, 11))
488: {
489: printf("nested agg\n");
490: treepr(agg);
491: }
492: # endif
493:
494: /* form list of bydomains */
495: lnodv[lnode(agg->left->left, lnodv, 0)] = 0;
496: usedmap = 0;
497:
498: De.de_hnext = &hlist[0];
499: De.de_hlimit = &hlist[30];
500:
501: /* find all possible replacements */
502: vars = modtree(&root, lnodv, &usedmap);
503:
504: /*
505: ** All references to a variable must be replaced
506: ** in order to use this aggregates by-domains.
507: */
508: if (usedmap && ((vars & usedmap) == 0))
509: {
510: # ifdef xDTR1
511: if (tTf(40, 7))
512: printf("Committed\n");
513: # endif
514: /* success. Committ the tree changes */
515: De.de_hnext->trepr = NULL;
516:
517: for (hl = &hlist[0]; tpr = hl->trepr; hl++)
518: {
519: /* get bydomain number */
520: i = hl->byno;
521:
522: /* get node being replaced */
523: tree = *tpr;
524:
525: /* if it is already a var, just change it */
526: if (tree->sym.type == VAR)
527: {
528: tree->sym.value.sym_var.varno = al->agvarno;
529: tree->sym.value.sym_var.attno = i + 2;
530: }
531: else
532: *tpr = makavar(lnodv[i], al->agvarno, i + 2);
533:
534: anyop = TRUE;
535: # ifdef xDTR1
536: if (tTf(40, 7))
537: {
538: printf("modified tree\n");
539: treepr(*tpr);
540: }
541: # endif
542: }
543: }
544: /* vars is now a map of the variables in the root */
545: treemap = vars;
546: }
547: }
548:
549: /* if any changes were made, get rid of the unnecessary links */
550: if (anyop)
551: chklink(root);
552: }
553:
554:
555:
556:
557: modtree(pnode, lnodv, replmap)
558: QTREE **pnode;
559: QTREE *lnodv[];
560: int *replmap;
561: {
562: register QTREE *tree;
563: register int vars, i;
564: QTREE *afcn;
565:
566: /* point up current node */
567: if ((tree = *pnode) == NULL)
568: return (0);
569:
570: /* examine each by-list for match on this subtree */
571: for (i = 0; afcn = lnodv[i]; i++)
572: {
573: if (sameafcn(tree, afcn->right))
574: {
575: # ifdef xDTR1
576: if (tTf(40, 9))
577: {
578: printf("potential Jackpot");
579: treepr(tree);
580: }
581: # endif
582: vars = varfind(tree, (QTREE *)NULL);
583: if (De.de_hnext == De.de_hlimit)
584: return (vars); /* no more room */
585:
586: /* record what needs to be done */
587: De.de_hnext->trepr = pnode;
588: De.de_hnext->byno = i;
589: De.de_hnext++;
590: *replmap |= vars;
591: return (0);
592: }
593: }
594: if (tree->sym.type == VAR)
595: return (01 << tree->sym.value.sym_var.varno);
596:
597: /* try the subtrees */
598: vars = modtree(&(tree->left), lnodv, replmap);
599: if ((vars & *replmap) == 0)
600: vars |= modtree(&(tree->right), lnodv, replmap);
601:
602: return (vars);
603: }
604:
605:
606: chklink(root)
607: QTREE *root;
608: {
609: register QTREE *r, *b, *last;
610:
611: last = root;
612:
613: for (r = last->right; r->sym.type != QLEND; r = r->right)
614: {
615: /* if this is an EQ node then check for an unnecessary compare */
616: if ((b = r->left)->sym.type == BOP && b->sym.value.sym_op.opno == opEQ)
617: {
618: if (sameafcn(b->left, b->right))
619: {
620: # ifdef xDTR1
621: if (tTf(40, 5))
622: {
623: printf("unnec clause\n");
624: treepr(b);
625: }
626: # endif
627: last->right = r->right;
628: continue;
629: }
630: }
631: last = r;
632: }
633: }
634:
635:
636:
637: sameafcn(q1, q2)
638: QTREE *q1, *q2;
639: {
640:
641: register QTREE *t1, *t2;
642: register int len;
643: int type;
644:
645: t1 = q1;
646: t2 = q2;
647:
648: if (!(t1 && t2))
649: return(!(t1 || t2));
650: len = (t1->sym.len & I1MASK) + SYM_HDR_SIZ;
651: type = t1->sym.type;
652: if (type == VAR)
653: len = sizeof(struct varnode);
654: if (type == AND)
655: len = 2;
656: if (!bequal(&t1->sym.type, &t2->sym.type, len))
657: return(0);
658: return(sameafcn(t1->left,t2->left) && sameafcn(t1->right,t2->right));
659: }
660: /*
661: ** varfind -- find all variables in the tree pointed to by "root".
662: ** Examine all parts of the tree except aggregates. For
663: ** aggregates, ignore simple aggregate and look only
664: ** at the by-lists of aggregate functions. If the aggregate
665: ** is "aghead" then ignore it. There is no reason to look
666: ** at yourself!!!!
667: ** This routine is called by byeval() to determine
668: ** whether to link the aggregate to the root tree.
669: **
670: ** Curiosity note: since the tree being examined has not been
671: ** processed by decomp yet, ckvar does not need to be called
672: ** since the var could not have been altered.
673: */
674:
675: varfind(root, aghead)
676: QTREE *root;
677: QTREE *aghead;
678: {
679: register QTREE *tree;
680: register int type;
681:
682: if ((tree = root) == NULL)
683: return (0);
684:
685: if ((type = tree->sym.type) == AGHEAD)
686: {
687: /* ignore if it matches aghead */
688: if (tree == aghead)
689: return (0);
690: /* if this is an aggregate function, look at bylist */
691: tree = tree->left;
692: if ((type = tree->sym.type) != BYHEAD)
693: return (0);
694: }
695:
696: if (type == VAR)
697: return (1 << tree->sym.value.sym_var.varno);
698:
699: return (varfind(tree->left, aghead) | varfind(tree->right, aghead));
700: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.