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