|
|
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.