From 2199bf4643514a3871e7139d334ee74b75af7eb4 Mon Sep 17 00:00:00 2001 From: Oliver Lehmann Date: Wed, 12 Jul 1989 09:56:55 +0000 Subject: [PATCH] ING_DB --- WEGA/contrib/ingres/dbs/src/decomp/byeval.c | 316 +++++++++++++++ WEGA/contrib/ingres/dbs/src/ovqp/findsimps.c | 384 +++++++++++++++++++ 2 files changed, 700 insertions(+) create mode 100644 WEGA/contrib/ingres/dbs/src/decomp/byeval.c create mode 100644 WEGA/contrib/ingres/dbs/src/ovqp/findsimps.c diff --git a/WEGA/contrib/ingres/dbs/src/decomp/byeval.c b/WEGA/contrib/ingres/dbs/src/decomp/byeval.c new file mode 100644 index 0000000..25a5962 --- /dev/null +++ b/WEGA/contrib/ingres/dbs/src/decomp/byeval.c @@ -0,0 +1,316 @@ +# include +# include "gen.h" +# include "../h/dbs.h" +# include "../h/aux.h" +# include "../h/tree.h" +# include "../h/symbol.h" +# include "../h/pipes.h" +# include "decomp.h" + +/* +** BYEVAL - process aggregate function +** +** Byeval is passed the root of the original query +** tree and the root of the aggregate function to +** be processed. +** +** It first creates a temporary relation which will +** hold the aggregate result. The format of the relation +** is: +** SYSNAMExxxxxaa(count, by-dom1, ... , by-domn, ag1, ... , agm) +** +** The relation is moved into the range table and will become +** a part of the query. +** +** If there are any occurences of the variables +** from the by-domains, anywhere in the original query tree, +** the aggregate relation is linked on all by-domains in the +** original query tree. +** +** If the aggregate is unique, multivariable, or has a +** qualification, then special processing is done. +** +** If the aggregate is qualified then the by-domains are +** projected into the result relation. This guarantees that +** every value of the by-domains will be represented in the +** aggregate result. +** +** If the aggregate is unique or multivariable, then another +** temporary relation is created and the values which will be +** aggregated; along with the by-domains, are retrieved into +** the temporary relation. +** +** If unique, then duplicates are removed from the temporary relation. +** +** Next the result relation for the aggregate is modified +** to hash in order to speed up the processing of the aggregate +** and guarantee that there are no duplicates in the bylist. +** +** The aggregate is then run, and if a temporary relation was +** created (eg. unique or multivar aggregate) then it is destroyed. +** +*/ + + +QTREE *byeval(root, aghead, agvar) +QTREE *root; /* root of orig query */ +QTREE *aghead; /* root of ag fcn sub-tree */ +int agvar; /* variable number assigned to this aggregate */ +{ + register QTREE *q; + register QTREE *ag; + register QTREE *resdom; + register QTREE *r; + int temp_relnum; + int i; + int filled; + QTREE *lnodv[MAXDOM + 2]; + QTREE *save_node[MAXDOM + 2]; + char agbuf[AGBUFSIZ]; + char nums[2]; + int relnum; + register QTREE *byhead; + register QTREE **alnp; + int bydoms; + int bymap; + int primeag; + int srcmap; + extern int derror(); + extern QTREE *copytree(); + extern QTREE *makavar(); + extern QTREE *makresdom(); + extern QTREE *makroot(); + +# ifdef xDTR1 + AAtTfp(7, -1, "BYEVAL\n"); +# endif + + ag = aghead; + byhead = ag->left; + + /* first create the aggregate result relation */ + /* params for create */ + + initp(); /* init globals for setp */ + setp("0"); /* initial relstat field */ + relnum = rnum_alloc(); + setp(rnum_convert(relnum)); + setp("count"); /* domain 1 - count field per BY value */ + setp("i4"); /* format of count field */ + + i = bydoms = lnode(byhead->left, lnodv, 0); + lnodv[i] = 0; + alnp = &lnodv[++i]; + i = lnode(byhead->right, lnodv, i); + lnodv[i] = 0; + + domnam(lnodv, "by"); /* BY list domains */ + domnam(alnp, "ag"); /* aggregate value domains */ + + call_dbu(mdCREATE, FALSE); + + Rangev[agvar].relnum = relnum; +# ifdef xDTR1 + AAtTfp(7, 7, "agvar=%d,rel=%s\n", agvar, rnum_convert(relnum)); +# endif + + bymap = varfind(byhead->left, (QTREE *) 0); + + /* + ** Find all variables in the tree in which you are nested. + ** Do not look at any other aggregates in the tree. Just in + ** case the root is an aggregate, explicitly look at its + ** two descendents. + */ + srcmap = varfind(root->left, ag) | varfind(root->right, ag); +# ifdef xDTR1 + AAtTfp(7, 8, "bymap=0%o,srcmap=0%o\n", bymap, srcmap); +# endif + + if (bymap & srcmap) + modqual(root, lnodv, srcmap, agvar); + + /* if aggregate is unique or there is a qualification + ** or aggregate is multi-var, then special processing is done */ + + temp_relnum = NORESULT; + filled = FALSE; + primeag = prime(byhead->right); + if (ag->right->sym.type != QLEND || ((ROOT_NODE *) ag)->tvarc > 1 || primeag) + { + /* init a buffer for new tree components */ + initbuf(agbuf, AGBUFSIZ, AGBUFFULL, derror); + + /* make a root for a new tree */ + q = makroot(agbuf); + + /* + ** Create a RESDOM for each by-domain in the original + ** aggregate. Rather than using the existing by-domain + ** function, a copy is used instead. This is necessary + ** since that subtree might be needed later (if modqual()) + ** decided to use it. Decomp does not restore the trees + ** it uses and thus the by-domains might be altered. + */ + for (i = 0; r = lnodv[i]; i++) + { + resdom = makresdom(agbuf, r); + ((RES_NODE *) resdom)->resno = i + 2; + resdom->right = copytree(r->right, agbuf); + resdom->left = q->left; + q->left = resdom; + } + mapvar(q, 0); /* make maps on root */ +# ifdef xDTR1 + if (AAtTf(7, 2)) + printree(q, "by-domains"); +# endif + + /* if agg is qualified, project by-domains into result */ + if (ag->right->sym.type != QLEND) + { + filled = TRUE; + i = Sourcevar; /* save value */ + decomp(q, mdRETR, relnum); + Sourcevar = i; /* restore value */ + } + + /* if agg is prime or multivar, compute into temp rel */ + if (((ROOT_NODE *) ag)->tvarc > 1 || primeag) + { + q->right = ag->right; /* give q the qualification */ + ag->right = Qle; /* remove qualification from ag */ + + /* put aop resdoms on tree */ + for (i = bydoms + 1; r = lnodv[i]; i++) + { + resdom = makresdom(agbuf, r); + resdom->right = r->right; + resdom->left = q->left; + q->left = resdom; + + /* make aop refer to temp relation */ + r->right = makavar(resdom, FREEVAR, i); + } + + /* assign result domain numbers */ + for (resdom = q->left; resdom->sym.type != TREE; resdom = resdom->left) + ((RES_NODE *) resdom)->resno = --i; + + /* + ** change by-list in agg to reference new source rel. + ** Save the old bylist to be restored at the end of + ** this aggregate. + */ + for (i = 0; resdom = lnodv[i]; i++) + { + save_node[i] = resdom->right; + resdom->right = makavar(resdom, FREEVAR, i + 1); + } + + mapvar(q, 0); +# ifdef xDTR1 + if (AAtTf(7, 3)) + printree(q, "new ag src"); +# endif + + /* create temp relation */ + temp_relnum = mak_t_rel(q, "a", -1); + decomp(q, mdRETR, temp_relnum); + Rangev[FREEVAR].relnum = temp_relnum; + Sourcevar = FREEVAR; + if (primeag) + removedups(FREEVAR); +# ifdef xDTR1 + if (AAtTf(7, 4)) + printree(ag, "new agg"); +# endif + } + } + + /* set up parameters for modify to hash */ + initp(); + setp(rnum_convert(relnum)); + setp("hash"); /* modify the empty rel to hash */ + setp("num"); /* code to indicate numeric domain names */ + nums[1] = '\0'; + for (i = 0; i < bydoms; i++) + { + nums[0] = i + 2; + setp(nums); + } + setp(""); + + /* set up fill factor information */ + setp("minpages"); + if (filled) + { + setp("1"); + setp("fillfactor"); + setp("100"); + } + else + setp("10"); + specclose(relnum); + call_dbu(mdMODIFY, FALSE); + + + Newq = 1; + Newr = TRUE; + call_ovqp(ag, mdRETR, relnum); + + Newq = 0; + /* if temp relation was used, destroy it */ + if (temp_relnum != NORESULT) + { + for (i = 0; resdom = lnodv[i]; i++) + resdom->right = save_node[i]; + dstr_rel(temp_relnum); + } +} + + + + +modqual(root, lnodv, srcmap, agvar) +QTREE *root; +QTREE *lnodv[]; +int srcmap; +int agvar; +{ + register QTREE *and_eq; + register QTREE *afcn; + register int i; + extern QTREE *copytree(); + extern QTREE *makavar(); + extern QTREE *need(); + +# ifdef xDTR1 + AAtTfp(14, 5, "modqual 0%o\n", srcmap); +# endif + + for (i = 0; afcn = lnodv[i]; i++) + { + /* 'AND' node */ + and_eq = need(Qbuf, QT_HDR_SIZ + AND_SIZ); + and_eq->sym.type = AND; + and_eq->sym.len = AND_SIZ; + ((ROOT_NODE *) and_eq)->tvarc = 0; + ((ROOT_NODE *) and_eq)->lvarc = 0; + ((ROOT_NODE *) and_eq)->lvarm = 0; + ((ROOT_NODE *) and_eq)->rvarm = 0; + and_eq->right = root->right; + root->right = and_eq; + + /* 'EQ' node */ + and_eq->left = need(Qbuf, QT_HDR_SIZ + OP_SIZ); + and_eq = and_eq->left; + and_eq->sym.type = BOP; + and_eq->sym.len = OP_SIZ; + ((OP_NODE *) and_eq)->opno = (int) opEQ; + + /* bydomain opEQ var */ + and_eq->right = copytree(afcn->right, Qbuf); /* a-fcn (in Source) specifying BY domain */ + and_eq->left = makavar(afcn, agvar, i + 2); /* VAR ref BY domain */ + } +} diff --git a/WEGA/contrib/ingres/dbs/src/ovqp/findsimps.c b/WEGA/contrib/ingres/dbs/src/ovqp/findsimps.c new file mode 100644 index 0000000..2dbedd5 --- /dev/null +++ b/WEGA/contrib/ingres/dbs/src/ovqp/findsimps.c @@ -0,0 +1,384 @@ +# include +# include "gen.h" +# include "../h/dbs.h" +# include "../h/symbol.h" +# include "../h/tree.h" +# include "../h/pipes.h" +# include "ovqp.h" +# include "strategy.h" + +int Nsimp; /* Current no. entries in Simp vector */ +struct simp Simp[NSIMP]; + +/* +** Findsimps searches the qualification for +** occurances of simple clauses. In its +** current crude implementation it only finds +** clauses of the form: +** +** var relop constant or constant relop var +** +** it does not use simple clauses with 'OR's +** nor does it accept clauses of the form +** +** var relop constant + constant etc. +** +** Findsimps knows about pattern matching characters +** and treats char constants containing pm chars +** specially. For example +** var >= "xx*" --> var >= "xx" +** var <= "xx*" --> var <= "xx\0177" +** var = "xx*" --> var >= "xx" and var <= "xx\0177" +** If the first char is a pm char then the clause is not +** considered as a simple clause. Also notice that the conversion +** is done only once. If the next time Newq = FALSE, then findsimps() +** isn't called. This works because a pm char can only come from +** the user and not from a relation. Thus during tuple substition +** a constant with a pm will never change. +*/ + +findsimps() +{ + register SYMBOL *c; + register int t; + int length; + register SYMBOL **q; + int attno; + int rel; + int found; + SYMBOL *xc; + extern SYMBOL *cpsym(); + +# ifdef xOTR1 + AAtTfp(21, 0, "FINDSIMPS\n"); +# endif + Nsimp = 0; + found = FALSE; + q = Qlist; /* q holds pointer to qualification */ + + if (!q) + return (0); + + + for (t = ctou((*q)->type); t != QLEND; t = ctou((*++q)->type)) + { + switch (t) + { + case VAR: + attno = ctou(*(*q)->value); /* save att number */ + if ((t = ctou((*++q)->type)) == INT + || t == FLOAT || t == CHAR || t == S_VAR) + { + c = *q; /* save pointer to value symbol */ + t = ctou((*++q)->type); + if ((rel = relop(*q, FALSE)) >= 0 + && (t = ctou((*++q)->type)) == AND) + { + /* found a simple clause */ + found = TRUE; + } + } + break; + + case S_VAR: + case INT: + case FLOAT: + case CHAR: + c = *q++; + if ((t = ctou((*q)->type)) == VAR) + { + attno = ctou(*(*q)->value); + t = ctou((*++q)->type); + if ((rel = relop(*q, TRUE)) >= 0 && (t = ctou((*++q)->type)) == AND) + { + /* found a simple clause */ + found = TRUE; + } + } + } + if (found) + { + /* a simple clause has been found. + ** Check that the constant contains + ** at least one char before any pattern + ** matching char. If there is a pattern + ** matching char then special processing + ** must be done. + */ + + found = FALSE; + if (length = check(c)) + { + + /* + ** If length is zero then the first char was + ** a pattern matching char. If length < 0 then + ** no pattern matching char, and finally + ** if length > 0 then length is the number of + ** chars before the first pattern matching char + */ + if (length > 0) + { + switch (rel) + { + + case opEQ: + /* + ** Create two simple clauses: + ** One below the value and the + ** other above the value. + */ + xc = cpsym(c, length, opLTLE); + add_simp(xc, opLTLE, attno); + rel = (int) opGTGE; + /* fall through to GTGE case */ + + case opGTGE: + c = cpsym(c, length, opGTGE); + break; + + case opLTLE: + c = cpsym(c, length, opLTLE); + break; + } + } + + if (add_simp(c, rel, attno)) + break; /* no more room in simps */ + } + } + while (t != AND) /* skip to next AND */ + t = ctou((*++q)->type); + } +# ifdef xOTR1 + AAtTfp(21, 2, "FINDSIMPS: rets %d\n", Nsimp); +# endif + return (Nsimp); +} + + +/* +** RELOP determines whether a symbol is a +** usable relational operator ie. =,>,>=,<,<= +** +** returns the type of the relational +** operator if found, else it returns +** -1 +** +** Items are normalized to be in the form: +** var relop constant. If reverse is TRUE then +** complement the sense of the relop. Reverse will +** be TRUE is the simple clause was found in the +** form constant relop var. +*/ +relop(s, reverse) +register SYMBOL *s; +register int reverse; +{ + register int v; + + v = -1; /* assume failure */ + if (s->type == BOP) + { + switch (ctou(*s->value)) + { + case opEQ: + v = (int) opEQ; + break; + + case opLT: + case opLE: + v = (int) opLTLE; + if (reverse) + v = (int) opGTGE; + break; + + case opGT: + case opGE: + v = (int) opGTGE; + if (reverse) + v = (int) opLTLE; + break; + } + } + return (v); +} + + + +/* +** CHECK checks the symbol for +** pattern matching characters. +** If any are found then check returns +** the number of characters before the +** first pattern matching character. +** +** If no pattern matching chars are found +** then check returns -1. +** +** note that PAT_RBRAC need not be checked for +** since it is not a pattern matching char unless +** PAT_LBRAC appears before it. +** +** PAT_LBRAC is treated specially in cpsym(). +** If any are detected, then length until the +** first PAT_ANY or PAT_ONE is returned. +*/ +check(s) +register SYMBOL *s; +{ + register char *cp; + register int len; + register int flag; + +# ifdef xOTR1 + if (AAtTfp(21, 4, "CHECK: sym")) + prsym(s); +# endif + if (s->type == CHAR) + { + flag = FALSE; + cp = (char *) s->value; /* the string is a literal */ + len = ctou(s->len); + while (len--) + { + switch (*cp++) + { + case PAT_ANY: + case PAT_ONE: + return ((ctou(s->len)) - len - 1); + + case PAT_LBRAC: + flag = TRUE; + } + } + if (flag) + return (ctou(s->len)); /* constant had PAT_LBRAC char */ + } + return (-1); /* ok */ +} + + +# ifdef EBCDIC +# define LAST_CHAR 0377 +# else +# define LAST_CHAR 0177 +# endif + +/* +** CPSYM -- copy a symbol to a new buffer area. +** If op is opLTLE then add a pad character +** whose value is the largest possible char +** value. +** +** If any ranges of characters are found, +** then the lowest/highest char is taken from +** range. +*/ +SYMBOL *cpsym(konst, len, op) +SYMBOL *konst; +int len; +int op; +{ + register SYMBOL *s; + register char *cp; + register int i; + register char *sp; + register int c; + register int nc; + extern char *Ovqpbuf; + extern char *need(); + + i = len; + len += SYM_HDR_SIZ; + if (op == (int) opLTLE) + len++; + s = (SYMBOL *) need(Ovqpbuf, len); + s->type = CHAR; + sp = (char *) s->value; + cp = (char *) konst->value; + + while (i--) + { + /* copy chars processing LBRAC chars if any */ + if ((c = *cp++) == PAT_LBRAC) + { + /* if string is empty, ignore it */ + if (i == 0) + break; + + c = *cp++; + i--; + + if (c == PAT_RBRAC) + continue; /* empty [] */ + + while (i-- && ((nc = *cp++) != PAT_RBRAC)) + { + /* ignore '-' */ + if (nc == '-') + continue; + + /* check for char larger/smaller than 'c' */ + if (op == (int) opLTLE) + { + if (nc > c) + c = nc; + } + else + { + if (nc < c) + c = nc; + } + } + } + + *sp++ = c; /* copy next char */ + } + if (op == (int) opLTLE) + *sp++ = LAST_CHAR; + s->len = sp - (char *) s->value; + + return (s); +} + + +/* +** ADD_SIMP -- add a simple clause to the list of +** simple clauses. As a side effect the Nsimp +** is incremented. If there is no room return +** TRUE else return FALSE +*/ +add_simp(konst, rel, attno) +register SYMBOL *konst; +register int rel; +int attno; +{ + register struct simp *s; + + if (Nsimp == NSIMP) + return (TRUE); /* no more room */ + + s = &Simp[Nsimp++]; + + s->att = attno; + s->konst = konst; + s->relop = rel; + +# ifdef xOTR1 + if (AAtTf(21, 3)) + prsimp(s); +# endif + + return (FALSE); +} + + +# ifdef xOTR1 +prsimp(s) +register struct simp *s; +{ + printf("simp:relop=%d,att=%d,val=", s->relop, s->att); + prsym(s->konst); +} +# endif