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: }