# include # include # include # include "globs.h" # include SCCSID(@(#)selectv.c 8.1 12/31/84) /* ** SELECTV -- Select a variable for substitution ** ** Selectv is called to determinimume the "best" variable ** to substitute for. The algorithm used is based on ** the Wong/Youseffi paper ERL M78/17. Selectv returns ** the variable to be substituted or it returns -1 which ** indicates that there is a relation with no tuples. ** If there is only one variable left, it is of course ** the one choosen. ** ** For cases of more than one variable, a variable with ** 0 or 1 tuples will always be choosen. Otherwise the ** variable with the smallest "costfunction" will be selected. ** In case of a tie, the variable with the smallest tuple count ** is selected. ** ** The costfunction is: ** |Ri| ** ______ ** Peffective i ** ** where |Ri| = cardinality of variable i. ** and Peff = The number of pages needed to be accessed to ** safisfy a query on Ri assuminimumg all other ** variables have been substituted for. ** ** ** Peff is only an estimate. The estimate is based on the ** storage structure of Ri and on whether Ri is used in ** the target list. Considering only equality clauses, ** the relation's structure is examinimumed to see if any ** can be used effectively. The following assumptions are ** made: ** useful hash: Peff = 1 ** useful isam: Peff = 2 ** useful hash sec index: Peff = 2 ** useful isam sec index: Peff = 3 ** ** If there is no useful structure or if the relation is ** a heap then: ** Peff = number of pages Ri occupies ** If the relation is not in the target list then its ** function is only an existence test. Scanning can and ** is stopped the first time a tuple is found which satisfies. ** We assume that on the average only 1/4 of the pages ** will have to be examinimumed. ** ** Parameters: ** root - root of the query ** ** Returns: ** The variable to substitute for ** or ** -1 if the query is false ** ** Side Effects: ** can cause a relation to be opened since ** ckpkey needs to know the key structure. ** ** Called By: ** decompy, decompz ** ** Trace Flags: ** 44 */ selectv(root) register QTREE *root; { int minimum, var, map, i; register struct rang_tab *rt, *rx; long costfunc(), lx, lt; map = root->sym.value.sym_root.lvarm | root->sym.value.sym_root.rvarm; minimum = -1; lx = 0; rx = NULL; for (i = 1, var = 0; map; i <<= 1, var++) { if ((map & i) == 0) continue; map &= ~i; rt = &De.de_rangev[var]; if (rx == NULL) { rx = rt; minimum = var; if (map == 0 || rt->rtcnt < 2) break; lx = costfunc(root, var, rt); } else { if (rt->rtcnt < 2) { rx = rt; minimum = var; break; } lt = costfunc(root, var, rt); if (lt < lx) { rx = rt; minimum = var; lx = lt; } } } if (minimum == -1) syserr("selectv:no source var"); # ifdef xDTR1 if (tTf(44, 1)) { printf("selectv:%d,tups=%ld,", minimum, rx->rtcnt); printf("cf=%ld,", lx); nodepr(root); } # endif if (rx->rtcnt == 0) minimum = -1; return (minimum); } long costfunc(root, var, rx) QTREE *root; int var; struct rang_tab *rx; { register struct rang_tab *r; register int i; register char *lp; char linkmap[MAXDOM]; long rel_page(), l; int c_bug; r = rx; for (lp = linkmap, i = MAXDOM; i--; ) *lp++ = 0; i = var; /* ** The c-compiler does not know how to generate code ** for the assignment of an short to a long inside ** an "if" expression. Therefore the variable "c_bug" ** is assigned the value of ckpkey inside the "if". ** The value is assigned to "l" in the "else". */ if (!findlinks(root, -1, i, linkmap) || (c_bug = ckpkey(linkmap, i)) == 0) { l = rel_pages(r->rtcnt, r->rtwid); /* if not in target list, assume 1/4 */ if ((root->sym.value.sym_root.lvarm & (01 << i)) == 0) { l >>= 2; if (l == 0) l = 1; } } else l = c_bug; /* l could not be assigned directly above */ l = r->rtcnt / l; # ifdef xDTR1 if (tTf(44, 3)) printf("costfunc %d is %ld\n", i, l); # endif return (l); }