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