1: # include "../ingres.h" 2: # include "../tree.h" 3: # include "../symbol.h" 4: # include "decomp.h" 5: 6: /* 7: ** BYEVAL - process aggregate function 8: ** 9: ** Byeval is passed the root of the original query 10: ** tree and the root of the aggregate function to 11: ** be processed. 12: ** 13: ** It first creates a temporary relation which will 14: ** hold the aggregate result. The format of the relation 15: ** is: 16: ** _SYSxxxxxaa(count, by-dom1, ... , by-domn, ag1, ... , agm) 17: ** 18: ** The relation is moved into the range table and will become 19: ** a part of the query. 20: ** 21: ** If there are any occurences of the variables 22: ** from the by-domains, anywhere in the original query tree, 23: ** the aggregate relation is linked on all by-domains in the 24: ** original query tree. 25: ** 26: ** If the aggregate is unique, multivariable, or has a 27: ** qualification, then special processing is done. 28: ** 29: ** If the aggregate is qualified then the by-domains are 30: ** projected into the result relation. This guarantees that 31: ** every value of the by-domains will be represented in the 32: ** aggregate result. 33: ** 34: ** If the aggregate is unique or multivariable, then another 35: ** temporary relation is created and the values which will be 36: ** aggregated; along with the by-domains, are retrieved into 37: ** the temporary relation. 38: ** 39: ** If unique, then duplicates are removed from the temporary relation. 40: ** 41: ** Next the result relation for the aggregate is modified 42: ** to hash in order to speed up the processing of the aggregate 43: ** and guarantee that there are no duplicates in the bylist. 44: ** 45: ** The aggregate is then run, and if a temporary relation was 46: ** created (eg. unique or multivar aggregate) then it is destroyed. 47: ** 48: */ 49: 50: 51: struct querytree *byeval(root, aghead, agvar) 52: struct querytree *root; /* root of orig query */ 53: struct querytree *aghead; /* root of ag fcn sub-tree */ 54: int agvar; /* variable number assigned to this aggregate */ 55: 56: { 57: 58: register struct querytree *q, *ag, *resdom; 59: struct querytree *r; 60: int temp_relnum, i, filled; 61: struct querytree *lnodv[MAXDOM+2], *save_node[MAXDOM+2]; 62: char agbuf[AGBUFSIZ]; 63: char nums[2]; 64: int relnum; 65: struct querytree *byhead, **alnp; 66: int bydoms, bymap, primeag, srcmap; 67: extern int derror(); 68: extern struct querytree *makroot(), *makresdom(), *copytree(), *makavar(); 69: 70: # ifdef xDTR1 71: if (tTf(7, -1)) 72: printf("BYEVAL\n"); 73: # endif 74: 75: ag = aghead; 76: byhead = ag->left; 77: 78: /* first create the aggregate result relation */ 79: /* params for create */ 80: 81: initp(); /* init globals for setp */ 82: setp("0"); /* initial relstat field */ 83: relnum = rnum_alloc(); 84: setp(rnum_convert(relnum)); 85: setp("count"); /* domain 1 - count field per BY value */ 86: setp("i4"); /* format of count field */ 87: 88: i = bydoms = lnode(byhead->left, lnodv, 0); 89: lnodv[i] = 0; 90: alnp = &lnodv[++i]; 91: i = lnode(byhead->right, lnodv, i); 92: lnodv[i] = 0; 93: 94: domnam(lnodv, "by"); /* BY list domains */ 95: domnam(alnp, "ag"); /* aggregate value domains */ 96: 97: call_dbu(mdCREATE, FALSE); 98: 99: Rangev[agvar].relnum = relnum; 100: # ifdef xDTR1 101: if (tTf(7, 7)) 102: printf("agvar=%d,rel=%s\n", agvar, rnum_convert(relnum)); 103: # endif 104: 105: bymap = varfind(byhead->left, NULL); 106: 107: /* 108: ** Find all variables in the tree in which you are nested. 109: ** Do not look at any other aggregates in the tree. Just in 110: ** case the root is an aggregate, explicitly look at its 111: ** two descendents. 112: */ 113: srcmap = varfind(root->left, ag) | varfind(root->right, ag); 114: # ifdef xDTR1 115: if (tTf(7, 8)) 116: printf("bymap=%o,srcmap=%o\n", bymap, srcmap); 117: # endif 118: 119: if (bymap & srcmap) 120: modqual(root, lnodv, srcmap, agvar); 121: 122: /* if aggregate is unique or there is a qualification 123: ** or aggregate is multi-var, then special processing is done */ 124: 125: temp_relnum = NORESULT; 126: filled = FALSE; 127: primeag = prime(byhead->right); 128: if (ag->right->sym.type != QLEND || ((struct qt_root *)ag)->tvarc > 1 || primeag) 129: { 130: /* init a buffer for new tree components */ 131: initbuf(agbuf, AGBUFSIZ, AGBUFFULL, &derror); 132: 133: /* make a root for a new tree */ 134: q = makroot(agbuf); 135: 136: /* 137: ** Create a RESDOM for each by-domain in the original 138: ** aggregate. Rather than using the existing by-domain 139: ** function, a copy is used instead. This is necessary 140: ** since that subtree might be needed later (if modqual()) 141: ** decided to use it. Decomp does not restore the trees 142: ** it uses and thus the by-domains might be altered. 143: */ 144: for (i = 0; r = lnodv[i]; i++) 145: { 146: resdom = makresdom(agbuf, r); 147: ((struct qt_res *)resdom)->resno = i + 2; 148: resdom->right = copytree(r->right, agbuf); 149: resdom->left = q->left; 150: q->left = resdom; 151: } 152: mapvar(q, 0); /* make maps on root */ 153: # ifdef xDTR1 154: if (tTf(7, 2)) 155: printree(q, "by-domains"); 156: # endif 157: 158: /* if agg is qualified, project by-domains into result */ 159: if (ag->right->sym.type != QLEND) 160: { 161: filled = TRUE; 162: i = Sourcevar; /* save value */ 163: decomp(q, mdRETR, relnum); 164: Sourcevar = i; /* restore value */ 165: } 166: 167: /* if agg is prime or multivar, compute into temp rel */ 168: if (((struct qt_root *)ag)->tvarc > 1 || primeag) 169: { 170: q->right = ag->right; /* give q the qualification */ 171: ag->right = Qle; /* remove qualification from ag */ 172: 173: /* put aop resdoms on tree */ 174: for (i = bydoms + 1; r = lnodv[i]; i++) 175: { 176: resdom = makresdom(agbuf, r); 177: resdom->right = r->right; 178: resdom->left = q->left; 179: q->left = resdom; 180: 181: /* make aop refer to temp relation */ 182: r->right = makavar(resdom, FREEVAR, i); 183: } 184: 185: /* assign result domain numbers */ 186: for (resdom = q->left; resdom->sym.type != TREE; resdom = resdom->left) 187: ((struct qt_res *)resdom)->resno = --i; 188: 189: /* 190: ** change by-list in agg to reference new source rel. 191: ** Save the old bylist to be restored at the end of 192: ** this aggregate. 193: */ 194: for (i = 0; resdom = lnodv[i]; i++) 195: { 196: save_node[i] = resdom->right; 197: resdom->right = makavar(resdom, FREEVAR, i + 1); 198: } 199: 200: mapvar(q, 0); 201: # ifdef xDTR1 202: if (tTf(7, 3)) 203: printree(q, "new ag src"); 204: # endif 205: 206: /* create temp relation */ 207: temp_relnum = mak_t_rel(q, "a", -1); 208: decomp(q, mdRETR, temp_relnum); 209: Rangev[FREEVAR].relnum = temp_relnum; 210: Sourcevar = FREEVAR; 211: if (primeag) 212: removedups(FREEVAR); 213: # ifdef xDTR1 214: if (tTf(7, 4)) 215: printree(ag, "new agg"); 216: # endif 217: } 218: } 219: 220: /* set up parameters for modify to hash */ 221: initp(); 222: setp(rnum_convert(relnum)); 223: setp("hash"); /* modify the empty rel to hash */ 224: setp("num"); /* code to indicate numeric domain names */ 225: nums[1] = '\0'; 226: for (i = 0; i < bydoms; i++) 227: { 228: nums[0] = i + 2; 229: setp(nums); 230: } 231: setp(""); 232: 233: /* set up fill factor information */ 234: setp("minpages"); 235: if (filled) 236: { 237: setp("1"); 238: setp("fillfactor"); 239: setp("100"); 240: } 241: else 242: { 243: setp("10"); 244: } 245: specclose(relnum); 246: call_dbu(mdMODIFY, FALSE); 247: 248: 249: Newq = 1; 250: Newr = TRUE; 251: call_ovqp(ag, mdRETR, relnum); 252: 253: Newq = 0; 254: /* if temp relation was used, destroy it */ 255: if (temp_relnum != NORESULT) 256: { 257: for (i = 0; resdom = lnodv[i]; i++) 258: resdom->right = save_node[i]; 259: dstr_rel(temp_relnum); 260: } 261: } 262: 263: 264: 265: 266: modqual(root, lnodv, srcmap, agvar) 267: struct querytree *root; 268: struct querytree *lnodv[]; 269: int srcmap; 270: int agvar; 271: { 272: register struct querytree *and_eq, *afcn; 273: register int i; 274: struct querytree *copytree(), *need(), *makavar(); 275: 276: # ifdef xDTR1 277: if (tTf(14, 5)) 278: printf("modqual %o\n", srcmap); 279: # endif 280: 281: for (i = 0; afcn = lnodv[i]; i++) 282: { 283: /* `AND' node */ 284: and_eq = need(Qbuf, 12); 285: and_eq->sym.type = AND; 286: and_eq->sym.len = 6; 287: ((struct qt_root *)and_eq)->tvarc = ((struct qt_root *)and_eq)->lvarc = ((struct qt_root *)and_eq)->lvarm = ((struct qt_root *)and_eq)->rvarm = 0; 288: and_eq->right = root->right; 289: root->right = and_eq; 290: 291: /* `EQ' node */ 292: and_eq->left = need(Qbuf, 8); 293: and_eq = and_eq->left; 294: and_eq->sym.type = BOP; 295: and_eq->sym.len = 2; 296: ((struct qt_op *)and_eq)->opno = opEQ; 297: 298: /* bydomain opEQ var */ 299: and_eq->right = copytree(afcn->right, Qbuf); /* a-fcn (in Source) specifying BY domain */ 300: and_eq->left = makavar(afcn, agvar, i+2); /* VAR ref BY domain */ 301: } 302: }