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