From 930486b59cf42bbc5a7902ae93b6a23f2dde49e4 Mon Sep 17 00:00:00 2001 From: Oliver Lehmann Date: Wed, 19 Apr 1989 07:25:22 +0000 Subject: [PATCH] ING_DB --- WEGA/contrib/ingres/dbs/src/decomp/ageval.c | 168 ++++ .../contrib/ingres/dbs/src/decomp/aggregate.c | 722 ++++++++++++++++++ WEGA/contrib/ingres/dbs/src/libq/IIcvar.c | 65 ++ WEGA/contrib/ingres/dbs/src/libq/IIglobals.h | 60 ++ WEGA/contrib/ingres/dbs/src/libq/IIn_ret.c | 125 +++ WEGA/contrib/ingres/dbs/src/libq/IIretrieve.c | 66 ++ WEGA/contrib/ingres/dbs/src/libq/IIw_left.c | 116 +++ WEGA/contrib/ingres/dbs/src/parser/format.c | 333 ++++++++ 8 files changed, 1655 insertions(+) create mode 100644 WEGA/contrib/ingres/dbs/src/decomp/ageval.c create mode 100644 WEGA/contrib/ingres/dbs/src/decomp/aggregate.c create mode 100644 WEGA/contrib/ingres/dbs/src/libq/IIcvar.c create mode 100644 WEGA/contrib/ingres/dbs/src/libq/IIglobals.h create mode 100644 WEGA/contrib/ingres/dbs/src/libq/IIn_ret.c create mode 100644 WEGA/contrib/ingres/dbs/src/libq/IIretrieve.c create mode 100644 WEGA/contrib/ingres/dbs/src/libq/IIw_left.c create mode 100644 WEGA/contrib/ingres/dbs/src/parser/format.c diff --git a/WEGA/contrib/ingres/dbs/src/decomp/ageval.c b/WEGA/contrib/ingres/dbs/src/decomp/ageval.c new file mode 100644 index 0000000..8b8a72a --- /dev/null +++ b/WEGA/contrib/ingres/dbs/src/decomp/ageval.c @@ -0,0 +1,168 @@ +# 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" + +/* +** AGEVAL -- evaluate simple aggregate. +** +** Uses trace flag 5 +** +** Ageval is passed the tree of a simple aggregate, +** and an array of space to store the results. The +** amount of space actually allocated is stored in +** (*result)->sym.len +** +** If the aggregate is unique (eg. countu, sumu, avgu) +** or if the aggregate is multi-variable, special +** processing is done. A temporary relation is formed +** with a result domain for each single agg in the tree. +** Decomp is called to retrieve +** the values to be aggregated into that relation. +** +** If the aggregate is unique, then duplicates are +** removed from the temporary relation. +** +** Next the aggregate is run on either the original relation +** or on the temporary relation. +** +** Finally the result is read from OVQP and if a +** temporary relation was used, it is destroyed. +** +*/ + + +QTREE *ageval(tree, result) +QTREE *tree; /* root of aggregate */ +QTREE *result[]; /* space for results */ +{ + register QTREE *aghead; + register QTREE *resdom; + register QTREE *aop; + register QTREE *newtree; + register int temp_relnum; + register int i; + QTREE *lnodv[MAXDOM + 2]; + char agbuf[AGBUFSIZ]; + extern int derror(); + extern QTREE *makavar(); + extern QTREE *makroot(); + extern QTREE *makresdom(); + + aghead = tree; + aop = aghead->left; + temp_relnum = NORESULT; + + /* if PRIME or multi-var, form aggregate domain in temp relation */ + if (prime(aop) || ((ROOT_NODE *) aghead)->tvarc > 1) + { + initbuf(agbuf, AGBUFSIZ, AGBUFFULL, derror); + + lnodv[lnode(aop, lnodv, 0)] = 0; + + /* create new tree for retrieve and give it the qualification */ + newtree = makroot(agbuf); + newtree->right = aghead->right; + aghead->right = Qle; + + /* put a resdom on new tree for each aop in orig tree */ + /* make each aop in orig tree reference new relation */ + for (i = 0; aop = lnodv[i]; ) + { + /* create resdom for new tree */ + resdom = makresdom(agbuf, aop); + ((RES_NODE *) resdom)->resno = ++i; + resdom->right = aop->right; + + /* connect it to newtree */ + resdom->left = newtree->left; + newtree->left = resdom; + + /* make orig aop reference new relation */ + aop->right = makavar(resdom, FREEVAR, i); + } + + /* make result relation */ + temp_relnum = mak_t_rel(newtree, "a", -1); + + /* prepare for query */ + mapvar(newtree, 0); + decomp(newtree, mdRETR, temp_relnum); + Rangev[FREEVAR].relnum = temp_relnum; + Sourcevar = FREEVAR; + + /* if prime, remove dups */ + if (prime(aghead->left)) + { + /* modify to heapsort */ + removedups(FREEVAR); + } + + } + + Newq = 1; + Newr = TRUE; + + call_ovqp(aghead, mdRETR, NORESULT); /* call ovqp with no result relation */ + Newq = 0; + + /* pick up results */ + readagg_result(result); + + /* if temp relation was created, destroy it */ + if (temp_relnum != NORESULT) + dstr_rel(temp_relnum); + +} + +prime(aop) +QTREE *aop; + +/* +** Determine if an aggregate contains any +** prime aggregates. Note that there might +** be more than one aggregate. +*/ + +{ + register QTREE *a; + + a = aop; + do + { + switch (a->sym.value[0]) + { + case opCNTU: + case opSUMU: + case opAVGU: + return (TRUE); + } + } while (a = a->left); + return (FALSE); +} + +removedups(var) +register int var; +/* +** Remove dups from an unopened relation +** by calling heapsort +*/ +{ + register char *p; + extern char *rangename(); + + closer1(var); /* guarantee that relation has been closed */ + initp(); + p = rangename(var); /* get name of relation */ +# ifdef xDTR1 + AAtTfp(5, 1, "removing dups from %s\n", p); +# endif + setp(p); + setp("heapsort"); + setp("num"); + call_dbu(mdMODIFY, FALSE); +} diff --git a/WEGA/contrib/ingres/dbs/src/decomp/aggregate.c b/WEGA/contrib/ingres/dbs/src/decomp/aggregate.c new file mode 100644 index 0000000..7be7c1e --- /dev/null +++ b/WEGA/contrib/ingres/dbs/src/decomp/aggregate.c @@ -0,0 +1,722 @@ +# include +# include "gen.h" +# include "../h/dbs.h" +# include "../h/access.h" +# include "../h/aux.h" +# include "../h/tree.h" +# include "../h/symbol.h" +# include "../h/pipes.h" +# include "decomp.h" + +struct agglist +{ + QTREE **father; /* addr of pointer to you */ + QTREE *agpoint; /* pointer to aghead */ + QTREE *agfather; /* is your father an aggregate? */ + int agvarno; /* var # assigned to aggr fnct */ +}; + +struct hitlist +{ + QTREE **trepr; /* position in tree to be changed */ + int byno; /* by-list position */ +}; + +static struct agglist *Aggnext; + +aggregate(root) +QTREE *root; +/* +** AGGREGATE - replace aggregates with their values +** +** Aggregate attempts to optimize aggregate processing +** wherever possible. It replaces aggregates with their +** values, and links aggregate functions which have +** identical by-lists together. +** +** Note that for the sake of this code, A "prime" +** aggregate is one in which duplicates are removed. +** These are COUNTU, SUMU, and AVGU. +** +** Aggregate first forms a list of all aggregates in +** the order they should be processed. +** +** For each aggregate, it looks at all other aggregates +** to see if there are two simple aggregates +** or if there is another aggregate funtion with the +** same by-list. +** +** An attempt is made to run +** as many aggregates as possible at once. This can be +** done only if two or more aggregates have the same +** qualifications and in the case of aggregate functions, +** they must have identical by-lists. +** Even then, certain combinations +** of aggregates cannot occure together. The list is +** itemized later in the code. +** +** Aggregate calls BYEVAL or AGEVAL to actually process +** aggregate functions or aggregates respectively. +** +*/ +{ + struct agglist alist[MAXAGG + 1]; + QTREE *rlist[MAXAGG + 1]; + register struct agglist *al; + register QTREE *agg; + register QTREE *aop1; + register QTREE *r; + register struct agglist *al1; + register QTREE *aop; + register QTREE *agg1; + int i; + int simple_agg; + int varmap; + int attcnt; + int anyagg; + int attoff; + int twidth; + extern QTREE *makavar(); + extern QTREE *agspace(); + + al = alist; + Aggnext = al; + + findagg(&root, root); /* generate list of all aggregates */ + Aggnext->agpoint = 0; /* mark end of the list */ + anyagg = 0; + + varmap = ((ROOT_NODE *) root)->lvarm | ((ROOT_NODE *) root)->rvarm; + + /* process each aggregate */ + for ( ; agg = al->agpoint; al++) + { + + /* is this still an aggregate? */ + if (agg->sym.type != AGHEAD) + continue; + mapvar(agg, 0); /* map the aggregate tree */ + anyagg++; + + Sourcevar = bitpos(((ROOT_NODE *) agg)->lvarm | ((ROOT_NODE *) agg)->rvarm); +# ifdef xDTR1 + AAtTfp(6, 4, "Sourcevar=%d,rel=%s\n", Sourcevar, rangename(Sourcevar)); +# endif + + simple_agg = (agg->left->sym.type == AOP); /* TRUE if no bylist */ + aop = agg->left; /* assume it was TRUE */ +# ifdef xDTR1 + AAtTfp(6, 0, "%s\n", simple_agg ? "agg" : "agg-func"); +# endif + if (simple_agg) + { + /* simple aggregate */ + rlist[0] = agspace(aop); + /* init width to the width of the aggregate */ + twidth = ctou(((VAR_NODE *) aop)->frml); + } + else + { + attoff = ((RES_NODE *) agg->left->left)->resno + 2; + aop = aop->right; /* find the AOP node */ + /* assign new source variable for aggregate */ + al->agvarno = getrange(&varmap); + /* compute width of bylist + count field */ + twidth = findwid(agg->left) + sizeof (long); + + /* make sure the aggregate does not exceed max dimensions */ + if (chkwidth(aop, &twidth, attoff)) + derror(AGFTOBIG); + } + attcnt = 1; /* one aggregate so far */ + + /* look for another identical aggregate */ + for (al1 = al + 1; agg1 = al1->agpoint; al1++) + { + + /* if agg is nested inside agg1 then ignore it */ + if (al->agfather == agg1 || agg1->sym.type != AGHEAD) + continue; + + /* split aggs and agg-func apart */ + /* check for identical aggregate */ + if (simple_agg) + { + aop1 = agg1->left; /* find AOP node */ + + if (aop1->sym.type != AOP) + continue; /* not a simple agg */ + + /* make sure they can be run together */ + if (checkagg(agg, aop, agg1, aop1) == 0) + continue; + + if ((i = sameagg(agg, aop1, attcnt)) >= 0) + { + /* found identical aggregate to rlist[i] */ + r = rlist[i]; + } + else + { + /* put this agg in with the others */ + + /* first make sure it won't exceed tuple length */ + if (chkwidth(aop1, &twidth, 0)) + continue; /* can't be included */ + r = rlist[attcnt++] = agspace(aop1); + + /* connect into tree */ + aop1->left = agg->left; + agg->left = aop1; + } + } + else + { + /* aggregate function */ + if (!sameafcn(agg->left->left, agg1->left->left)) + continue; + + aop1 = agg1->left->right; /* find AOP */ + + + if (checkagg(agg, aop, agg1, aop1) == 0) + { + /* same by-lists but they can't be run together */ + continue; + } + + if ((i = sameagg(agg, aop1, attcnt)) < 0) + { + /* make sure there is room */ + if (chkwidth(aop1, &twidth, attcnt + attoff)) + continue; + + /* add aggregate into tree */ + i = attcnt++; + + aop1->left = agg->left->right; + agg->left->right = aop1; + } + + r = makavar(aop1, al->agvarno, i + attoff); + } + /* replace aggregate in original tree with its value */ + *(al1->father) = r; + + /* remove aggregate from local list */ + agg1->sym.type = -1; +# ifdef xDTR1 + AAtTfp(6, 3, "including aghead 0%o\n", agg1); +# endif + } + + /* process aggregate */ + if (simple_agg) + { + rlist[attcnt] = 0; + ageval(agg, rlist); /* pass tree and result list */ + r = rlist[0]; + } + else + { + opt_bylist(alist, agg); + byeval(al->agfather, agg, al->agvarno); + r = makavar(aop, al->agvarno, attoff); + } + /* + ** Link result into tree. al->father hold the address + ** &(tree->left) or &(tree->right). + */ + *(al->father) = r; +# ifdef xDTR1 + if (AAtTf(6, 4)) + printree(*(al->father), "aggregate value"); +# endif + } + if (anyagg) + { + opt_bylist(alist, root); + mapvar(root, 0); /* remap main tree */ + } +} + +findagg(nodep, agf) +QTREE **nodep; +QTREE *agf; +/* +** findagg builds a list of all aggregates +** in the tree. It finds them by leftmost +** innermost first. +** +** The parameters represent: +** nodep: the address of the node pointing to you +** eg. &(tree->left) or &(tree->right) +** agf: the root node. or if we are inside +** a nested aggregate, the AGHEAD node +*/ +{ + register QTREE *q; + register QTREE *f; + register struct agglist *list; + register int agg; + + if (!(q = *nodep)) + return; + + f = agf; + if (agg = (q->sym.type == AGHEAD)) + f = q; /* this aggregate is now the father root */ + + /* find all aggregates below */ + findagg(&(q->left), f); + findagg(&(q->right), f); + + /* if this is an aggregate, put it on the list */ + if (agg) + { + list = Aggnext; + list->father = nodep; + list->agpoint = q; + list->agfather = agf; + Aggnext++; + } +} + + + +QTREE *agspace(aop) +QTREE *aop; +/* +** Agspace allocates space for the result of +** a simple aggregate. +*/ +{ + register QTREE *a; + register QTREE *r; + register int length; + extern QTREE *need(); + + a = aop; + length = ctou(((VAR_NODE *) a)->frml); + + r = need(Qbuf, length + QT_HDR_SIZ); + r->left = r->right = (QTREE *) 0; + r->sym.type = ((VAR_NODE *) a)->frmt; + r->sym.len = length; + + return (r); +} + + + +chkwidth(aop, widthp, domno) +QTREE *aop; +int *widthp; +int domno; + +/* +** Chkwidth -- make sure that the inclusion of another aggregate will +** not exceed the system limit. This means that the total width +** cannot exceed MAXTUP and the number of domains cannot exceed MAXDOM-1 +*/ + +{ + register int width; + + width = *widthp; + +# ifdef xDTR1 + AAtTfp(6, 10, "agg width %d,dom %d\n", width, domno); +# endif + + width += ctou(((VAR_NODE *) aop)->frml); + + if (width > AAmaxtup || domno > MAXDOM - 1) + return (1); + + *widthp = width; + return (0); +} + + +cprime(aop) +register QTREE *aop; +/* +** Determine whether an aggregate is prime +** or a don't care aggregate. Returns TRUE +** if COUNTU,SUMU,AVGU,MIN,MAX,ANY. +** Returns false if COUNT,SUM,AVG. +*/ +{ + register int i; + + i = TRUE; + switch (aop->sym.value[0]) + { + case opCNT: + case opSUM: + case opAVG: + i = FALSE; + } + return (i); +} + + +getrange(varmap) +int *varmap; +/* +** Getrange find a free slot in the range table +** for an aggregate function. +** +** If there are no free slots,derror is called +*/ +{ + register int i; + register int map; + register int bit; + + map = *varmap; + + for (i = 0; i < MAXRANGE; i++) + { + /* if slot is used, continue */ + if ((bit = 1 << i) & map) + continue; + + map |= bit; /* "or" bit into the map */ + *varmap = map; + +# ifdef xDTR1 + AAtTfp(6, 10, "Assn var %d, map 0%o\n", i, map); +# endif + + return (i); + } + derror(NODESCAG); +} + + +checkagg(aghead1, aop1, aghead2, aop2) +QTREE *aghead1; +QTREE *aop1; +QTREE *aghead2; +QTREE *aop2; +{ + register QTREE *aop_1; + register QTREE *aop_2; + register QTREE *agg1; + register int ok; + + /* two aggregate functions can be run together + ** according to the following table: + ** + ** prime !prime don't care + ** + ** prime afcn? never afcn? + ** !prime never always always + ** don't care afcn? always always + ** + ** don't care includes: ANY, MIN, MAX + ** afcn? means only if a-fcn's are identical + */ + + aop_1 = aop1; + aop_2 = aop2; + agg1 = aghead1; + + if (!prime(aop_1) && !prime(aop_2)) + ok = TRUE; + else + if (sameafcn(aop_1->right, aop_2->right)) + ok = cprime(aop_1) && cprime(aop_2); + else + ok = FALSE; + /* The two aggregates must range over the same variables */ + if ((((ROOT_NODE *) agg1)->lvarm | ((ROOT_NODE *) agg1)->rvarm) != (((ROOT_NODE *) aghead2)->lvarm | ((ROOT_NODE *) aghead2)->rvarm)) + ok = FALSE; + + + /* check the qualifications */ + if (ok) + ok = sameafcn(agg1->right, aghead2->right); + return (ok); +} + + +sameagg(aghead, newaop, agg_depth) +QTREE *aghead; +QTREE *newaop; +int agg_depth; +{ + register QTREE *agg; + register QTREE *newa; + register int i; + + agg = aghead; + newa = newaop; + agg = agg->left; + if (agg->sym.type == BYHEAD) + agg = agg->right; + + /* agg now points to first aggregate */ + for (i = 1; agg; agg = agg->left, i++) + if (sameafcn(agg->right, newa->right) && agg->sym.value[0] == newa->sym.value[0]) + { +# ifdef xDTR1 + AAtTfp(6, 6, "found identical aop 0%o\n", newa); +# endif + return (agg_depth - i); + } + + /* no match */ + return (-1); +} + + +static struct hitlist *Hnext; +static struct hitlist *Hlimit; + + +opt_bylist(alist, root) +struct agglist *alist; +QTREE *root; +{ + register struct agglist *al; + register QTREE *agg; + register struct hitlist *hl; + register QTREE **tpr; + register QTREE *tree; + QTREE *lnodv[MAXDOM+2]; + struct hitlist hlist[30]; + register int treemap; + register int i; + int anyop; + extern QTREE *makavar(); + int usedmap; + int vars; + + /* compute bitmap of all possible vars in tree (can include xtra vars) */ + treemap = ((ROOT_NODE *) root)->lvarm | ((ROOT_NODE *) root)->rvarm; + anyop = FALSE; + + /* scan the list of aggregates looking for one nested in root */ + for (al = alist; (agg = al->agpoint) && agg != root; al++) + { + if (agg->sym.type == AGHEAD && agg->left->sym.type == BYHEAD && + al->agfather == root) + { + + /* this aggregate function is nested in root */ + + /* make sure it has some vars of interest */ + if ((treemap & varfind(agg->left->left, (QTREE *) 0)) == 0) + continue; + +# ifdef xDTR1 + if (AAtTf(6, 11)) + printree(agg, "nested agg"); +# endif + + /* form list of bydomains */ + lnodv[lnode(agg->left->left, lnodv, 0)] = 0; + usedmap = 0; + + Hnext = &hlist[0]; + Hlimit = &hlist[30]; + + /* find all possible replacements */ + vars = modtree(&root, lnodv, &usedmap); + + /* + ** All references to a variable must be replaced + ** in order to use this aggregates by-domains. + */ + if (usedmap && ((vars & usedmap) == 0)) + { +# ifdef xDTR1 + AAtTfp(6, 7, "Committed\n"); +# endif + /* success. Committ the tree changes */ + Hnext->trepr = (QTREE **) 0; + + for (hl = &hlist[0]; tpr = hl->trepr; hl++) + { + /* get bydomain number */ + i = hl->byno; + + /* get node being replaced */ + tree = *tpr; + + /* if it is already a var, just change it */ + if (tree->sym.type == VAR) + { + ((VAR_NODE *) tree)->varno = al->agvarno; + ((VAR_NODE *) tree)->attno = i + 2; + } + else + *tpr = makavar(lnodv[i], al->agvarno, i + 2); + + anyop = TRUE; +# ifdef xDTR1 + if (AAtTf(6, 7)) + printree(*tpr, "modified tree"); +# endif + } + } + /* vars is now a map of the variables in the root */ + treemap = vars; + } + } + + /* if any changes were made, get rid of the unnecessary links */ + if (anyop) + chklink(root); +} + + + + +modtree(pnode, lnodv, replmap) +QTREE **pnode; +QTREE *lnodv[]; +int *replmap; +{ + register QTREE *tree; + register int vars; + register int i; + register QTREE *afcn; + + /* point up current node */ + if (!(tree = *pnode)) + return (0); + + /* examine each by-list for match on this subtree */ + for (i = 0; afcn = lnodv[i]; i++) + { + if (sameafcn(tree, afcn->right)) + { +# ifdef xDTR1 + if (AAtTf(6, 9)) + printree(tree, "potential Jackpot"); +# endif + vars = varfind(tree, (QTREE *) 0); + if (Hnext == Hlimit) + return (vars); /* no more room */ + + /* record what needs to be done */ + Hnext->trepr = pnode; + Hnext->byno = i; + Hnext++; + *replmap |= vars; + return (0); + } + } + if (tree->sym.type == VAR) + return (01 << ((VAR_NODE *) tree)->varno); + + /* try the subtrees */ + vars = modtree(&(tree->left), lnodv, replmap); + if ((vars & *replmap) == 0) + vars |= modtree(&(tree->right), lnodv, replmap); + + return (vars); +} + + +chklink(root) +QTREE *root; +{ + register QTREE *r; + register QTREE *b; + register QTREE *last; + + last = root; + + for (r = last->right; r->sym.type != QLEND; r = r->right) + { + /* if this is an EQ node then check for an unnecessary compare */ + if ((b = r->left)->sym.type == BOP && ((OP_NODE *) b)->opno == (int) opEQ) + { + if (sameafcn(b->left, b->right)) + { +# ifdef xDTR1 + if (AAtTf(6, 5)) + printree(b, "unnec clause"); +# endif + last->right = r->right; + continue; + } + } + last = r; + } +} + + + +sameafcn(t1, t2) +register QTREE *t1; +register QTREE *t2; +{ + register int len; + register int type; + + if (!(t1 && t2)) + return (!(t1 || t2)); + + if (!AAbequal(&t1->sym, &t2->sym, TYP_LEN_SIZ)) + return (0); + + len = ctou(t1->sym.len); + if ((type = t1->sym.type) == VAR) + len = VAR_HDR_SIZ; + else if (type == AND) + len = 0; + if (len && !AAbequal(t1->sym.value, t2->sym.value, len)) + return (0); + return (sameafcn(t1->left, t2->left) && sameafcn(t1->right, t2->right)); +} + + +varfind(root, aghead) +QTREE *root; +QTREE *aghead; + +/* +** varfind -- find all variables in the tree pointed to by "root". +** Examine all parts of the tree except aggregates. For +** aggregates, ignore simple aggregate and look only +** at the by-lists of aggregate functions. If the aggregate +** is "aghead" then ignore it. There is no reason to look +** at yourself!!!! +** This routine is called by byeval() to determine +** whether to link the aggregate to the root tree. +** +** Curiosity note: since the tree being examined has not been +** processed by decomp yet, ckvar does not need to be called +** since the var could not have been altered. +*/ + +{ + register QTREE *tree; + register int type; + + + if (!(tree = root)) + return (0); + + if ((type = tree->sym.type) == AGHEAD) + { + /* ignore if it matches aghead */ + if (tree == aghead) + return (0); + /* if this is an aggregate function, look at bylist */ + tree = tree->left; + if ((type = tree->sym.type) != BYHEAD) + return (0); + } + + if (type == VAR) + return (1 << ((VAR_NODE *) tree)->varno); + + return (varfind(tree->left, aghead) | varfind(tree->right, aghead)); +} diff --git a/WEGA/contrib/ingres/dbs/src/libq/IIcvar.c b/WEGA/contrib/ingres/dbs/src/libq/IIcvar.c new file mode 100644 index 0000000..a1826fc --- /dev/null +++ b/WEGA/contrib/ingres/dbs/src/libq/IIcvar.c @@ -0,0 +1,65 @@ +# include +# include "gen.h" +# include "../h/dbs.h" +# include "../h/symbol.h" +# include "../h/pipes.h" +# include "IIglobals.h" + +/* +** IIcvar -- write C variable values to parser +** +** IIcvar is used to write the contents +** of a C-variable to the QL parser. +** +** Floats are converted to doubles first. +*/ +IIcvar(addr, type, length) +register char *addr; +register int type; +register int length; +{ + char t; + double d; +# ifndef NO_F4 + struct _flt_ + { + float flt; + }; +# endif + + switch (type) + { +# ifndef NO_F4 + case opFLT: + /* convert from f4 to f8 */ + d = ((struct _flt_ *) addr)->flt; + addr = (char *) &d; + length = sizeof (double); + type = opDOUBLE; + break; +# endif + + case opSTRING: + length = IIlength(addr) + 1; /* length includes null byte at end */ + + case opINT: + case opLONG: + case opDOUBLE: + break; + + default: + IIsyserr("CVAR: Unbekannter Typ %d", type); + } + +# ifdef xETR1 + if (IIdebug) + printf("CVAR: typ %d, len %d\n", type, length); +# endif + + t = type; + if (IIwrpipe(P_NORM, &IIoutpipe, IIw_down, &t, sizeof (char)) != sizeof (char)) + IIsyserr("CVAR: WRITE TYP"); + + if (IIwrpipe(P_NORM, &IIoutpipe, IIw_down, addr, length) != length) + IIsyserr("CVAR: WRITE VALUE len=%d", length); +} diff --git a/WEGA/contrib/ingres/dbs/src/libq/IIglobals.h b/WEGA/contrib/ingres/dbs/src/libq/IIglobals.h new file mode 100644 index 0000000..ee82fba --- /dev/null +++ b/WEGA/contrib/ingres/dbs/src/libq/IIglobals.h @@ -0,0 +1,60 @@ +/* IIGLOBALS.H -- EQL run-time library globals */ +/* */ +/* In this file are defined the global variables, */ +/* and manifest constants used in the EQL run-time */ +/* routines. All globals must start with "II". */ +/* */ +/* Requires: */ +/* The "pipfrmt" structure is the dbs interprocess */ +/* pipe buffer structure defined in ".../pipes.h". */ +/* MAXDOM is defined in h/dbs.h. */ + +# define opINT 1 +# ifndef NO_F4 +# define opFLT 2 +# endif +# define opSTRING 3 +# define opDOUBLE 4 +# define opCHAR 5 +# define opLONG 6 + +# define EQL '&' + +extern char *IIproc_name; /* file name */ +extern int IIline_no; /* line no */ +extern int IIdebug; /* debug flag */ +extern int IIqlpid; /* process id of dbs */ +extern int IIin_retrieve; /* set if inside a retrieve */ +extern int IIndoms; /* # of domains in this retrieve */ +extern int IIdoms; /* index into source field of buf */ +extern long IItupcnt; /* # tuples which satified last */ + /* update query */ +extern int IIw_down; /* pipe descriptors for */ +extern int IIr_down; /* parser communcation */ +extern int IIr_front; /* pipe descriptor for */ + /* ovqp ommunication */ +extern int IIerrflag; /* error flag. Set in IIerror, */ + /* cleared in IIsync */ +extern int (*IIprint_err)(); /* wether or not error messgs */ + /* should be printed */ +extern int IIret_err(); /* returns its integer arg for */ + /* (*IIprint_err)() */ +extern int IIno_err(); /* returns 0 for (*IIprint_err)() */ +extern int (*IIo_print)(); /* a one value stack for */ + /* temporarily turned off printing */ + /* of errors. Done in [IIw_left.c */ + /* and IIw_right.c]. */ + +struct retsym +{ + char type; + char len; + char *addr; +}; +extern struct retsym IIretsym[]; /* retrieve table */ +extern struct retsym IIr_sym; /* type, length fields used by new */ + /* EQL in IIn_ret and IIn_get */ + +extern struct pipfrmt IIeinpipe; /* the data pipe structure */ +extern struct pipfrmt IIinpipe; /* the control pipe struct */ +extern struct pipfrmt IIoutpipe; /* the pipe for writing queries */ diff --git a/WEGA/contrib/ingres/dbs/src/libq/IIn_ret.c b/WEGA/contrib/ingres/dbs/src/libq/IIn_ret.c new file mode 100644 index 0000000..2de1af9 --- /dev/null +++ b/WEGA/contrib/ingres/dbs/src/libq/IIn_ret.c @@ -0,0 +1,125 @@ +# include +# include "gen.h" +# include "../h/dbs.h" +# include "../h/aux.h" +# include "../h/symbol.h" +# include "../h/tree.h" +# include "../h/pipes.h" +# include "IIglobals.h" + +/* +** IIn_ret -- get next domain in a retrieve +** +** Gets the next domain in a retrieve from the data +** pipe. If an error occurred previously in the tuple, +** will not load the c-var with the value of the domain. +** Performs the conversion from the gotten type to +** the expected type. +** +** Signals any errors and calls IIerror() accordingly. +** +** Expects the type and length of the next data item in +** IIr_sym. +*/ +IIn_ret(addr, type) +char *addr; +int type; +{ + register struct retsym *ret; + register int length; + char *s; + char temp[MAXFIELD + 1]; + extern char *IIitos(); + + + if (IIerrflag && IIerrflag != 1001) + return; /* error, no data will be coming, or the */ + /* rest of the query should be skipped */ + + if (length = ctou((ret = &IIr_sym)->len)) + if (IIrdpipe(P_NORM, &IIeinpipe, IIr_front, temp, length) != length) + IIsyserr("N_RET: READ VALUE len=%d", length); + +# ifdef xETR1 + if (IIdebug) + printf("N_RET: addr 0%o typ %d len %d ret.typ %d IIerrflag %d\n", + addr, type, length, ret->type, IIerrflag); +# endif + + IIdoms++; + switch (type) + { + case opINT: + type = INT; + length = sizeof (short); + break; + + case opLONG: + type = INT; + length = sizeof (long); + break; + +# ifndef NO_F4 + case opFLT: + type = FLOAT; + length = sizeof (float); + break; +# endif + + case opDOUBLE: + type = FLOAT; + length = sizeof (double); + break; + + case opSTRING: + type = CHAR; + /* with the current implementation the length is not known */ + length = MAXFIELD; + break; + + default: + IIsyserr("N_RET: Unbekannter Typ %d", type); + } + + switch (ret->type) + { + case INT: + case FLOAT: + if (type == CHAR) + { + IIerrflag = 1000; + goto error; + } + if (IIconvert(temp, IIerrflag? temp: addr, + ret->type, ctou(ret->len), type, length) < 0) + { + IIerrflag = 1001; + goto error; + } + break; + + case CHAR: + if (type != CHAR) + { + IIerrflag = 1002; +error: + s = IIitos(IIdoms); + IIerror(IIerrflag, 1, &s); + return; + } + if (!IIerrflag) + { + IIbmove(temp, addr, ctou(ret->len)); + + /* null terminate string */ + addr[ctou(ret->len)] = '\0'; + } + break; + + default: + IIsyserr("N_RET: READ TYP %d", ret->type); + } + + if (IIrdpipe(P_NORM, &IIeinpipe, IIr_front, ret, TYP_LEN_SIZ) != TYP_LEN_SIZ) + IIsyserr("N_RET: READ TYP_LEN"); +} diff --git a/WEGA/contrib/ingres/dbs/src/libq/IIretrieve.c b/WEGA/contrib/ingres/dbs/src/libq/IIretrieve.c new file mode 100644 index 0000000..2d8806d --- /dev/null +++ b/WEGA/contrib/ingres/dbs/src/libq/IIretrieve.c @@ -0,0 +1,66 @@ +# include +# include "gen.h" +# include "../h/dbs.h" +# include "../h/aux.h" +# include "../h/symbol.h" +# include "../h/pipes.h" +# include "IIglobals.h" + +/* +** IIretrieve is called once for each element +** in the target list of a retrieve. +** +** The purpose is to set up the IIretsym structure +** for IIgettup. +*/ +IIretrieve(addr, type) +char *addr; +int type; +{ + register struct retsym *sym; + register int t; + register int l; + + sym = &IIretsym[IIndoms++]; + switch (type) + { + case opINT: + t = INT; + l = sizeof (short); + break; + + case opLONG: + t = INT; + l = sizeof (long); + break; + +# ifndef NO_F4 + case opFLT: + t = FLOAT; + l = sizeof (float); + break; +# endif + + case opDOUBLE: + t = FLOAT; + l = sizeof (double); + break; + + case opSTRING: + t = CHAR; + /* with the current implementation the length is not known */ + l = MAXFIELD; + break; + + default: + IIsyserr("RETRIEVE: Unbekannter Typ %d", type); + } + sym->type = t; + sym->len = l; + sym->addr = addr; + +# ifdef xETR1 + if (IIdebug) + printf("RETRIEVE: IIndoms %d typ %d len %d\n", IIndoms, t, l); +# endif +} diff --git a/WEGA/contrib/ingres/dbs/src/libq/IIw_left.c b/WEGA/contrib/ingres/dbs/src/libq/IIw_left.c new file mode 100644 index 0000000..29b527d --- /dev/null +++ b/WEGA/contrib/ingres/dbs/src/libq/IIw_left.c @@ -0,0 +1,116 @@ +# include +# include "gen.h" +# include "../h/dbs.h" +# include "../h/pipes.h" +# include "IIglobals.h" + +/* +** IIW_LEFT -- writes down a "tupret's" target list. +** +** Parameters: +** string -- a char * to a string containing everything +** inside the equivalent "retrieve" statement, +** but instead of result domain names, the string +** should have '%', where +** is the QL type of the resulting C variable. +** To escape a '%' use 2 ("%%"). +** 'String' is left unchanged after the call. +** argv -- a vector of pointers to the +** corresponding C variables. +** +** Usage: +** argv[0] = &double_var; +** argv[1] = &int_var; +** IIw_left("%f8 = i.double, %i2=i.ifield", argv); +*/ +IIw_left(string, argv) +char *string; +char **argv; +{ + register char *b_st; + register char *e_st; + register char **av; + register int type; + extern char *IIitos(); + +# ifdef xETR1 + if (IIdebug) + printf("LEFT: string \"%s\"\n", string); +# endif + av = argv; + for (b_st = e_st = string; *e_st; ) + { + if (*e_st != '%') + { + e_st++; + continue; + } + + /* provide escape method */ + if (e_st[1] == '%') + { + e_st[1] = '\0'; + IIwrite(b_st); + /* leave string intact */ + e_st[1] = '%'; + b_st = e_st = &e_st[2]; + continue; + } + *e_st = '\0'; + IIwrite(b_st); + *e_st++ = '%'; + IIwrite(" RET_VAR "); + + switch (*e_st) + { + case 'f': + type = *++e_st - '0'; + switch (type) + { +# ifndef NO_F4 + case sizeof (float): + type = opFLT; + break; +# endif + + case sizeof (double): + type = opDOUBLE; + break; + + default: + goto error_label; + } + break; + + case 'i': + type = *++e_st - '0'; + switch (type) + { + case sizeof (long): + type = opLONG; + break; + + case sizeof (short): + type = opINT; + break; + + default: +error_label: + IIerror(IIerrflag = 1003, 1, &string); + /* make sure that part already written down */ + /* will cause an error, and ignore that error */ + IIwrite(","); + IIo_print = IIprint_err; + IIprint_err = IIno_err; + } + break; + + case 'c': + type = opSTRING; + break; + } + IIretrieve(*av++, type); + b_st = ++e_st; + } + IIwrite(b_st); +} diff --git a/WEGA/contrib/ingres/dbs/src/parser/format.c b/WEGA/contrib/ingres/dbs/src/parser/format.c new file mode 100644 index 0000000..f9fb158 --- /dev/null +++ b/WEGA/contrib/ingres/dbs/src/parser/format.c @@ -0,0 +1,333 @@ +# include +# include "gen.h" +# include "../h/dbs.h" +# include "../h/aux.h" +# include "../h/tree.h" +# include "../h/pipes.h" +# include "../h/symbol.h" +# include "parser.h" + +char Trfrmt; /* format for type checking */ +char Trfrml; /* format length for type checking */ + +/* +** FORMAT +** routine to compute the format of the result relation attributes +** it is called after ATTLOOKUP so the tuple defining the current +** attribute is already available. +** if the element is a function of more than one attribute, the result +** domain format is computed by the following rules: +** - no fcns allowed on character attributes +** - fcn of integer attribs is an integer fcn with +** length = MAX(length of all attributes) +** - fcn of floating point attribs is a floating point +** fcn with length = MIN(length of all attribs) +** - fcn of integer and floating attributes is a +** floating fcn with length = MIN(length of all floating +** attributes) +*/ +format(result1) +QTREE *result1; +{ + register char rfrmt; + register char rfrml; + register QTREE *result; + struct constop *cpt; + extern struct out_arg AAout_arg; + extern struct constop Coptab[]; + + result = result1; + switch (result->sym.type) + { + case VAR: + rfrmt = ((VAR_NODE *) result)->frmt; + rfrml = ((VAR_NODE *) result)->frml; + break; + + case AOP: + switch (((OP_NODE *) result)->opno) + { + case opAVG: + case opAVGU: + rfrmt = FLOAT; + rfrml = sizeof (double); + if (((AOP_NODE *) result)->agfrmt == CHAR) + /* character domain not allowed in these aggs */ + yyerror(AVGTYPE, (char *) 0); + break; + + case opCNT: + case opCNTU: + rfrmt = INT; + rfrml = sizeof (long); + break; + + case opANY: + rfrmt = INT; + rfrml = sizeof (short); + break; + + case opSUM: + case opSUMU: + rfrmt = ((AOP_NODE *) result)->agfrmt; + rfrml = ((AOP_NODE *) result)->agfrml; + if (rfrmt == CHAR) + /* no char domains for these aggs */ + yyerror(SUMTYPE, (char *) 0); + break; + + default: + rfrmt = ((AOP_NODE *) result)->agfrmt; + rfrml = ((AOP_NODE *) result)->agfrml; + break; + } + break; + + case AGHEAD: + /* + ** can get format info from the AOP node because + ** it already has format info computed + */ + if (result->left->sym.type == AOP) + { + /* no by-list */ + rfrmt = ((VAR_NODE *) result->left)->frmt; + rfrml = ((VAR_NODE *) result->left)->frml; + } + else + { + /* skip over by-list */ + rfrmt = ((VAR_NODE *) result->left->right)->frmt; + rfrml = ((VAR_NODE *) result->left->right)->frml; + } + break; + + case RESDOM: + format(result->right); + return; + + case INT: + case FLOAT: + case CHAR: + rfrmt = result->sym.type; + rfrml = result->sym.len; + break; + + case COP: + for (cpt = Coptab; cpt->copname; cpt++) + { + if (((OP_NODE *) result)->opno == cpt->copnum) + { + rfrmt = cpt->coptype; + rfrml = cpt->coplen; + break; + } + } + if (!cpt->copname) + AAsyserr(18002, ((OP_NODE *) result)->opno); + break; + + case UOP: + switch (((OP_NODE *) result)->opno) + { + case opATAN: + case opCOS: + case opGAMMA: + case opLOG: + case opSIN: + case opSQRT: + case opEXP: + format(result->left); + if (Trfrmt == CHAR) + /* + ** no character expr in FOP + ** if more ops are added, must change error message */ + yyerror(FOPTYPE, (char *) 0); + + case opFLT8: + /* float8 is type conversion and can have char values */ + rfrmt = FLOAT; + rfrml = sizeof (double); + break; + +# ifndef NO_F4 + case opFLT4: + rfrmt = FLOAT; + rfrml = sizeof (float); + break; +# endif + + case opINT1: + rfrmt = INT; + rfrml = sizeof (char); + break; + + case opINT2: + rfrmt = INT; + rfrml = sizeof (short); + break; + + case opINT4: + rfrmt = INT; + rfrml = sizeof (long); + break; + + case opASCII: + format(result->left); + rfrmt = CHAR; + rfrml = Trfrml; + if (Trfrmt == INT) + { + if (Trfrml == sizeof (short)) + rfrml = AAout_arg.i2width; + else if (Trfrml == sizeof (long)) + rfrml = AAout_arg.i4width; + else if (Trfrml == sizeof (char)) + rfrml = AAout_arg.i1width; + else + AAsyserr(18003, Trfrml); + break; + } + if (Trfrmt == FLOAT) + { + if (Trfrml == sizeof (double)) + rfrml = AAout_arg.f8width; +# ifndef NO_F4 + else if (Trfrml == sizeof (float)) + rfrml = AAout_arg.f4width; +# endif + else + AAsyserr(18004, Trfrml); + break; + } + if (Trfrmt == CHAR) + break; + AAsyserr(18005, Trfrmt); + + case opNOT: + if (!Qlflag) + AAsyserr(18006); + return; + + case opMINUS: + case opPLUS: + format(result->right); + if (Trfrmt == CHAR) + /* no chars for these unary ops */ + yyerror(UOPTYPE, (char *) 0); + return; + + case opABS: + format(result->left); + if (Trfrmt == CHAR) + /* no char values in fcn */ + yyerror(FOPTYPE, (char *) 0); + return; + + default: + AAsyserr(18007, ((OP_NODE *) result)->opno); + } + break; + + case BOP: + switch (((OP_NODE *) result)->opno) + { + + case opEQ: + case opNE: + case opLT: + case opLE: + case opGT: + case opGE: + if (!Qlflag) + AAsyserr(18008); + format(result->right); + rfrmt = Trfrmt; + format(result->left); + if ((rfrmt == CHAR) != (Trfrmt == CHAR)) + /* type conflict on relational operator */ + yyerror(RELTYPE, (char *) 0); + return; + + case opADD: + case opSUB: + case opMUL: + case opDIV: + format(result->left); + rfrmt = Trfrmt; + rfrml = Trfrml; + format(result->right); + if (rfrmt == CHAR || Trfrmt == CHAR) + /* no opns on characters allowed */ + yyerror(NUMTYPE, (char *) 0); + if (rfrmt == FLOAT || Trfrmt == FLOAT) + { + if (rfrmt == FLOAT && Trfrmt == FLOAT) + { + if (Trfrml < rfrml) + rfrml = Trfrml; + } + else if (Trfrmt == FLOAT) + rfrml = Trfrml; + rfrmt = FLOAT; + } + else + if (Trfrml > rfrml) + rfrml = Trfrml; + break; + + case opMOD: + format(result->left); + rfrmt = Trfrmt; + rfrml = Trfrml; + format(result->right); + if (rfrmt != INT || Trfrmt != INT) + /* mod operator not defined */ + yyerror(MODTYPE, (char *) 0); + if (Trfrml > rfrml) + rfrml = Trfrml; + break; + + case opPOW: + format(result->right); + rfrmt = Trfrmt; + rfrml = Trfrml; + format(result->left); + if (rfrmt == CHAR || Trfrmt == CHAR) + { + /* no char values for pow */ + yyerror(NUMTYPE, (char *) 0); + } +# ifndef NO_F4 + if ((rfrmt == FLOAT && rfrml == sizeof (float)) + || (Trfrmt == FLOAT && Trfrml == sizeof (float))) + { + rfrmt = FLOAT; + rfrml = sizeof (float); + } + else +# endif + { + rfrmt = FLOAT; + rfrml = sizeof (double); + } + break; + + case opCONCAT: + format(result->left); + rfrmt = Trfrmt; + rfrml = Trfrml; + format(result->right); + if (rfrmt != CHAR || Trfrmt != CHAR) + /* only character domains allowed */ + yyerror(CONCATTYPE, (char *) 0); + rfrml += Trfrml; + break; + + default: + AAsyserr(18009, ((OP_NODE *) result)->opno); + } + } + Trfrmt = rfrmt; + Trfrml = rfrml; +}