|
|
1.1 root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.