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

Defined functions

aggregate defined in line 8; used 1 times
agspace defined in line 279; used 3 times
checkagg defined in line 381; used 2 times
chklink defined in line 606; used 1 times
chkwidth defined in line 302; used 3 times
cprime defined in line 331; used 2 times
  • in line 411(2)
findagg defined in line 243; used 3 times
getrange defined in line 353; used 1 times
modtree defined in line 557; used 3 times
opt_bylist defined in line 458; used 2 times
sameafcn defined in line 637; used 8 times
sameagg defined in line 426; used 2 times
varfind defined in line 675; used 7 times
Last modified: 1986-04-17
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1810
Valid CSS Valid XHTML 1.0 Strict