|
|
1.1 root 1: # include <ingres.h>
2: # include <symbol.h>
3: # include <aux.h>
4: # include <tree.h>
5: # include "globs.h"
6: # include <sccs.h>
7:
8: SCCSID(@(#)decision.c 7.1 2/5/81)
9:
10: /*
11: ** DECISION -- This file contains code related to deciding how to
12: ** process the remaining query. The main routine is decision()
13: ** and the other routines are called only by decision. The routine
14: ** in this file include:
15: **
16: ** Decision -- Decides how to process a query.
17: **
18: ** Fixtl -- Determines the target list for each component.
19: **
20: ** Fixresult -- Determines the result relation for the next query
21: **
22: ** Fixrange -- Adjust the range table after a query
23: **
24: ** Fixovlap -- Fixes trees in cases where reduction is used
25: **
26: ** Rmovlap -- Restores trees in cases where reduction was used.
27: **
28: ** Listcomp -- Debugging routine.
29: */
30: /*
31: ** Decision is given a subquery and decides how to process it.
32: ** The choices are:
33: ** Disjoint pieces -- The original query had disjoint components.
34: ** Do each component separately.
35: ** Reduction -- The query is joined by a single variable.
36: ** Reduce the query on that joining variable
37: ** and do each component separately.
38: ** Substitution -- The query is neither disjoint nor reducible.
39: ** Process by tuple substitution.
40: **
41: ** Notice that decision() is recursive and will call itself on each
42: ** subcomponent it decides to do. Decision calls various support
43: ** routines in the file "reduction.c".
44: */
45:
46: decision(root, qmode, result_num, buf)
47: QTREE *root;
48: int qmode;
49: int result_num;
50: char *buf;
51: {
52: register QTREE **qp;
53: register struct complist *clist;
54: register int ovlapvar;
55: struct complist *cp;
56: int i, onepiece, qtrue, map;
57: int mark, mark1, cand_map;
58: QTREE *tree, *newtree;
59: QTREE *qlist[MAXRANGE];
60: int newqmode;
61: int ovlaprelnum, newr;
62: int locrange[MAXRANGE];
63: extern QTREE *copy_ands();
64: extern struct complist *buildlist(), *order();
65: extern QTREE *construct();
66:
67: # ifdef xDTR1
68: if (tTf(37, -1))
69: {
70: printf("DECISION root=%x,vc=%d,res=%d\n", root, root->sym.value.sym_root.tvarc, result_num);
71: }
72: # endif
73: mark = markbuf(buf);
74: if (root->sym.value.sym_root.tvarc < 3)
75: {
76: /* setup to do as one single piece */
77: onepiece = TRUE;
78: }
79: else
80: {
81: /* break the query apart if possible */
82:
83: /* build component list */
84: clist = buildlist(root, buf);
85: # ifdef xDTR1
86: if (tTf(37, 2))
87: listcomp(clist, "Original Comp");
88: # endif
89:
90: /* is query completely connected or disjoint */
91: map = root->sym.value.sym_root.lvarm | root->sym.value.sym_root.rvarm;
92: onepiece = algorithm(clist, map);
93: # ifdef xDTR1
94: if (tTf(37, 1))
95: printf("Orig query %s\n", onepiece ? "connected" : "disjoint");
96: # endif
97: /* assume there is no joining variable */
98: ovlapvar = -1;
99:
100: if (onepiece)
101: {
102: /*
103: ** Try to reduce a single connected piece.
104: ** In turn each variable will be logically
105: ** removed from the query and a test will
106: ** be made to see if the query is still
107: ** connected.
108: */
109:
110: cand_map = map;
111: for (i = 1; cand_map; i <<= 1)
112: {
113: if ((cand_map & i) == 0)
114: continue;
115: cand_map &= ~i;
116: freebuf(buf, mark);
117: clist = buildlist(root, buf);
118: if (algorithm(clist, map & ~i) == 0)
119: {
120: ovlapvar = bitpos(i);
121: ovlaprelnum = De.de_rangev[ovlapvar].relnum;
122: onepiece = FALSE;
123: break;
124: }
125: }
126: # ifdef xDTR1
127: if (tTf(37, 1))
128: {
129: if (ovlapvar < 0)
130: printf("Query not reducible\n");
131: else
132: {
133: printf("Query Reducible on %d\n", ovlapvar);
134: if (tTf(37, 3))
135: listcomp(clist, "After reduct");
136: }
137: }
138: # endif
139: }
140:
141: /*
142: ** If query is more than one piece, build trees
143: ** for each piece.
144: */
145:
146: if (!onepiece)
147: {
148: /* order pieces */
149: clist = order(clist, ovlapvar);
150: # ifdef xDTR1
151: if (tTf(37, 4))
152: listcomp(clist, "After ordering");
153: # endif
154: cp = clist;
155: qp = qlist;
156: do
157: {
158: *qp++ = construct(root, cp, buf);
159: } while (cp = cp->nextcomp);
160: *qp++ = 0;
161: }
162: }
163:
164: /*
165: ** The query is now either the one original piece or
166: ** is in multiple pieces. The information in clist
167: ** has been thrown away and now the ordered pieces
168: ** will be processed.
169: */
170:
171: if (onepiece)
172: {
173: freebuf(buf, mark);
174: qtrue = decompy(root, qmode, result_num, buf);
175: }
176: else
177: {
178: /* the query is in pieces. prepare to process */
179:
180: newquery(locrange); /* save state of range table */
181:
182: /* determine the target list for each piece of the query */
183: for (qp = qlist; tree = *qp++; )
184: fixtl(tree, qp, ovlapvar, buf);
185:
186: /* adjust refs to ovlapvar since domain #'s could have changed */
187: fixovlap(qlist, ovlapvar, buf);
188:
189:
190: /* now process each component */
191: mark1 = markbuf(buf);
192: for (qp = qlist; tree = *qp++; )
193: {
194:
195: # ifdef xDTR1
196: if (tTf(37, 6))
197: {
198: printf("next piece\n");
199: treepr(tree);
200: }
201: # endif
202:
203: /* determine result relation name */
204: newr = fixresult(root, tree, &newqmode, qmode, result_num);
205:
206: /*
207: ** Run the query. If reduction is being
208: ** performed, the actual tree given to
209: ** the decision routine must be a copy
210: ** to protect from the recursive call changing
211: ** the tree. Any work done at this level,
212: ** must be to the original tree
213: */
214: newtree = tree;
215: if (ovlapvar != -1)
216: {
217: freebuf(buf, mark1);
218: newtree = copy_ands(tree, buf);
219: }
220: qtrue = decision(newtree, newqmode, newr, buf);
221:
222: /* fix up the range table */
223: fixrange(root, tree, ovlapvar, ovlaprelnum, newr);
224:
225: /* if last piece was false then done */
226: if (!qtrue)
227: break;
228:
229: }
230:
231: /* restore the trees */
232: rmovlap(qlist, ovlapvar);
233:
234: /* restore range table back to original */
235: endquery(locrange, TRUE); /* reopen previous range */
236:
237: /* return any buffer space used */
238: freebuf(buf, mark);
239: }
240:
241: /* all done with query */
242: return (qtrue);
243: }
244: /*
245: ** Fixresult -- Determine result relation for "tree" query.
246: ** If "tree" is the original target list piece then use the
247: ** original relation and mode.
248: ** If "tree" is a reduction piece then create a temporary relation
249: ** for it.
250: ** If "tree" is a disjoint piece then there is no target list nor
251: ** result relation.
252: **
253: ** Return:
254: ** result relation number
255: ** Side Effects:
256: ** *newmode is set to the query mode of the next piece
257: */
258:
259: fixresult(root, tree1, newmode, origmode, resnum)
260: QTREE *root;
261: QTREE *tree1;
262: int *newmode;
263: int origmode;
264: int resnum;
265: {
266: register QTREE *tree;
267: register int newresult;
268:
269: tree = tree1;
270: *newmode = mdRETR;
271: if (tree->left->sym.type != TREE)
272: {
273: if (tree != root)
274: {
275: /* make new result for reduction step */
276: newresult = mak_t_rel(tree, "r", -1);
277: }
278: else
279: {
280: /* final piece with original result and mode */
281: newresult = resnum;
282: *newmode = origmode;
283: }
284: }
285: else
286: newresult = NORESULT;
287: return (newresult);
288: }
289: /*
290: ** Update range table after a reduction has been processed.
291: ** Only the intermediate reductions will affect the range
292: ** table. The last piece does not.
293: */
294:
295: fixrange(root, tree, ovlapvar, reductnum, newrelnum)
296: QTREE *root;
297: QTREE *tree;
298: int ovlapvar;
299: int reductnum;
300: int newrelnum;
301: {
302: register int old;
303: register int i;
304: extern DESC *openr1();
305:
306: if (root != tree)
307: {
308: /* this is an intermediate piece */
309: i = ovlapvar;
310:
311: if (newrelnum >= 0)
312: {
313: old = new_range(i, newrelnum);
314: if (old != reductnum)
315: dstr_rel(old);
316: openr1(i);
317: }
318: }
319: }
320: /*
321: ** Fixovlap -- Adjust subsequent trees which reference the reduction var
322: **
323: ** If the first query in list redefines the reduction variable
324: ** (if any) then each subsequent query which references the
325: ** reduction variable is adjusted.
326: ** Since there may be multiple pieces,
327: ** subsequence redefinitions are done without
328: ** reallocating buffer space.
329: **
330: */
331:
332: fixovlap(qlist, ovlapvar, buf)
333: QTREE *qlist[];
334: int ovlapvar;
335: char *buf;
336: {
337: register QTREE **qp, *piece, **qp1;
338: QTREE *next;
339: int ovmap;
340: extern QTREE **mksqlist();
341:
342: ovmap = 1 << ovlapvar;
343:
344: /* for each piece, if it redefines ovlapvar, then fix up rest */
345: for (qp = qlist; piece = *qp++; )
346: {
347: if (piece->sym.value.sym_root.lvarm & ovmap)
348: {
349: for (qp1 = qp; next = *qp1++; )
350: {
351: if ((next->sym.value.sym_root.lvarm | next->sym.value.sym_root.rvarm) & ovmap)
352: {
353: tempvar(next, mksqlist(piece, ovlapvar), buf);
354: buf = NULL; /* do not allocate on subsequent refs */
355: }
356: }
357: }
358: }
359: }
360: /*
361: ** Rmovlap -- Restore query trees back to their original state.
362: **
363: ** Rmovlap undoes the effect of fixovlap(). Any references
364: ** to the reduction variable which were adjusted are now
365: ** reverted back to the original reference. Note that the
366: ** first piece is not effected by fixovlap.
367: */
368:
369: rmovlap(qlist, ovlapvar)
370: QTREE *qlist[];
371: int ovlapvar;
372: {
373: register QTREE **qp, *tree;
374: int ovmap;
375:
376: if (ovmap = (1 << ovlapvar))
377: {
378: /* for each piece, remove any tempvars */
379: for (qp = &qlist[1]; tree = *qp++; )
380: {
381: origvar(tree, mksqlist(tree, ovlapvar));
382: }
383: }
384: }
385: /*
386: ** Fixtl -- Determine what the target list of each tree should be.
387: **
388: ** Fixtl takes each query which references the reduction variable
389: ** and looks for references to that variable in subsequent queries.
390: ** Dfind will build a target list which includes every domain
391: ** which will later be referenced.
392: */
393:
394: fixtl(tree1, qp1, ovlapvar, buf)
395: QTREE *tree1;
396: QTREE *qp1[];
397: int ovlapvar;
398: char *buf;
399: {
400: register QTREE *tree, **qp, *next;
401: int var, map;
402: extern QTREE **mksqlist();
403:
404: tree = tree1;
405: var = ovlapvar;
406: map = 1 << var;
407:
408: /*
409: ** if the last tree referenced the overlap variable then
410: ** try to fix next tree
411: */
412: if (tree->sym.value.sym_root.rvarm & map)
413: {
414: qp = qp1;
415: while (next = *qp++)
416: {
417: if ((next->sym.value.sym_root.lvarm | next->sym.value.sym_root.rvarm) & map)
418: dfind(next, buf, mksqlist(tree, var));
419: }
420: }
421: }
422:
423:
424:
425: # ifdef xDTR1
426:
427: /*
428: ** This is strictly a debuggin routine used for
429: ** printing component lists.
430: */
431:
432: listcomp(list, mesg)
433: struct complist *list;
434: char *mesg;
435: {
436: register struct complist *c, *cl;
437: register int i;
438:
439: if (tTf(37, 14))
440: {
441: printf("%s\n", mesg);
442: i = -1;
443:
444: for (cl = list; cl; cl = cl->nextcomp)
445: {
446: i++;
447: printf("Component %d:map=%o\n", i, cl->bitmap);
448: for (c = cl; c; c = c->linkcomp)
449: {
450: printf("%x, ", c->clause);
451: if (tTf(37, 15))
452: {
453: treepr(c->clause->left);
454: nodepr(c->clause);
455: }
456: }
457: printf("\n");
458: }
459: }
460: }
461: # endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.