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