ING_DB
This commit is contained in:
parent
35b61c8634
commit
930486b59c
|
|
@ -0,0 +1,168 @@
|
|||
# include <stdio.h>
|
||||
# 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);
|
||||
}
|
||||
|
|
@ -0,0 +1,722 @@
|
|||
# include <stdio.h>
|
||||
# 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));
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
# include <stdio.h>
|
||||
# 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);
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
# include <stdio.h>
|
||||
# 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");
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
# include <stdio.h>
|
||||
# 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
|
||||
}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
# include <stdio.h>
|
||||
# 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 '%<dbs_type>', where <dbs_type>
|
||||
** 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);
|
||||
}
|
||||
|
|
@ -0,0 +1,333 @@
|
|||
# include <stdio.h>
|
||||
# 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;
|
||||
}
|
||||
Loading…
Reference in New Issue