2.11BSD/ingres/source/decomp/call_ovqp70.c
# include "../ingres.h"
# include "../aux.h"
# include "../unix.h"
# include "../access.h"
# include "../tree.h"
# include "../symbol.h"
# include "decomp.h"
# include "../ovqp/ovqp.h"
/*
** CALL_OVQP -- Routines which interface to the One Variable Query Processor.
**
** This file contains the routines associated with sending queries
** and receiving results from OVQP. The interface to these routines is
** still messy. Call_ovqp is given the query, mode, and result relation
** as parameters and gets the source relation, and two flags
** (Newq, Newr) as globals. The routines include:
**
** Call_ovqp -- Sends a One-var query to ovqp and flushes the pipe.
**
** Readresult -- Reads the result from a one-var query.
**
** Endovqp -- Informs ovqp that the query is over. Helps to synchronize
** the batch file (if any).
**
*/
int Qvptr; /* index into available Qvect space in ovqpnod() */
struct symbol *Qvect[MAXNODES];
char *Ovqpbuf;
char D_ovqp70 = 1; /* used for loading only. forces call_ovqp70 to be
** loaded instead of call_ovqp
*/
call_ovqp(qtree, mode, resultnum)
struct querytree *qtree;
int mode;
int resultnum;
/*
** Call_ovqp -- send query down pipe to ovqp and flush pipe.
** Inputs are:
** mode retrieve, append, etc.
** resultnum result relation id
** qtree the query
** Sourcevar (global) if >= 0 then source var
** Newq send NEWQ symbol
** Newr send NEWR symbol
*/
{
register struct querytree *tree;
register int i;
char *rangename();
struct symbol s;
extern int derror();
extern int Batchupd;
extern struct descriptor Inddes;
char ovqpbuf[LBUFSIZE];
struct descriptor *readopen(), *specopen();
# ifdef xOTM
if (tTf(76, 1))
timtrace(7, 0);
# endif
tree = qtree;
# ifdef xDTR1
if (tTf(8, -1))
{
if (tTf(8, 0))
printf("CALL_OVQP-\n");
if (tTf(8, 1))
{
if (Newq)
printree(tree, "new query to ovqp");
else
printf("query same as previous\n");
}
if (tTf(8, 2))
{
printf("Sourcevar=%d\t", Sourcevar);
if (Sourcevar >= 0)
printf("relid=%s\t", rangename(Sourcevar));
if (resultnum >= 0)
printf("Resultname=%s", rnum_convert(resultnum));
if (((struct qt_root *)tree)->rootuser)
printf(", userqry");
printf("\n");
}
}
# endif
/* assign mode of this query */
Ov_qmode = mode;
if (Newr)
{
Newr = FALSE;
}
if (resultnum >= 0)
Result = specopen(resultnum);
else
Result = NULL;
if (Sourcevar >= 0)
Source = readopen(Sourcevar);
else
Source = NULL;
/* assume this will be direct update */
Userqry = Buflag = FALSE;
if (((struct qt_root *)tree)->rootuser)
{
Userqry = TRUE;
/* handle batch file */
if (Result && Ov_qmode != mdRETR)
{
if (Batchupd || Result->relindxd > 0)
{
if (Bopen == 0)
{
if (Result->relindxd > 0)
opencatalog("indexes", 0);
if (i = openbatch(Result, &Inddes, Ov_qmode))
syserr("call_ovqp:opn batch %d", i);
Bopen = TRUE;
}
Buflag = TRUE;
}
}
}
/* now write the query list itself */
if (Newq)
{
Ovqpbuf = ovqpbuf;
initbuf(Ovqpbuf, LBUFSIZE, LISTFULL, &derror);
Qvptr = 0;
Alist = Bylist = Qlist = Tlist = NULL;
Targvc = ((struct qt_root *)tree)->lvarc;
Qualvc = bitcnt(((struct qt_root *)tree)->rvarm);
Agcount = 0;
if (tree->sym.type == AGHEAD)
{
Alist = &Qvect[0];
if (tree->left->sym.type == BYHEAD)
{
mklist(tree->left->right);
ovqpnod(tree->left); /* BYHEAD node */
Bylist = &Qvect[Qvptr];
mklist(tree->left->left);
}
else
mklist(tree->left);
}
else
{
if (tree->left->sym.type != TREE)
{
Tlist = &Qvect[0];
mklist(tree->left);
}
}
/* now for the qualification */
ovqpnod(tree); /* ROOT node */
if (tree->right->sym.type != QLEND)
{
Qlist = &Qvect[Qvptr];
mklist(tree->right);
}
ovqpnod(Qle); /* QLEND node */
}
/* Now call ovqp */
if (strategy())
{
# ifdef xOTM
if (tTf(76, 2))
timtrace(9, 0);
# endif
i = scan(); /* scan the relation */
# ifdef xOTM
if (tTf(76, 2))
timtrace(10, 0);
# endif
}
else
i = EMPTY;
# ifdef xOTM
if (tTf(76, 1))
timtrace(8, 0);
# endif
/* return result of query */
return (i == NONEMPTY); /* TRUE if tuple satisfied */
}
struct retcode Retcode; /* return code structure */
endovqp(ack)
int ack;
/*
** Endovqp -- Inform ovqp that processing is complete. "Ack" indicates
** whether to wait for an acknowledgement from ovqp. The overall
** mode of the query is sent followed by an EXIT command.
**
** Ovqp decides whether to use batch update or not. If ack == ACK
** then endovqp will read a RETVAL symbol from ovqp and return
** a token which specifies whether to call the update processor or not.
*/
{
register int i, j;
extern int Qry_mode;
if (ack != RUBACK)
{
if (Equel && Qry_mode == mdRETTERM)
equeleol(EXIT); /* signal end of retrieve to equel process */
}
i = NOUPDATE;
if (ack == ACK)
{
if (Bopen)
{
closebatch();
Bopen = FALSE;
i = UPDATE;
}
}
else
{
if (Bopen)
{
rmbatch();
Bopen = FALSE;
}
}
Retcode.rc_tupcount = Tupsfound;
closecatalog(FALSE);
return (i);
}
ovqpnod(n)
struct querytree *n;
/*
** Add node n to ovqp's list
*/
{
register struct symbol *s;
register struct querytree *q;
register int i;
extern struct querytree *ckvar(), *need();
q = n;
s = &q->sym;
/* VAR nodes must be specially processed */
if (s->type == VAR)
{
/* locate currently active VAR */
q = ckvar(q);
/* Allocate an ovqp var node for the VAR */
s = (struct symbol *) need(Ovqpbuf, 8);
s->len = 6;
s->value[0] = ((struct qt_var *)q)->attno;
((struct qt_v *)s)->vtype = ((struct qt_var *)q)->frmt;
((struct qt_v *)s)->vlen = ((struct qt_var *)q)->frml;
/* If VAR has been substituted for, get value */
if (((struct qt_var *)q)->valptr)
{
/* This is a substituted variable */
if (((struct qt_var *)q)->varno == Sourcevar)
syserr("ovqpnod:bd sub %d,%d", ((struct qt_var *)q)->varno, Sourcevar);
s->type = S_VAR;
((struct qt_v *)s)->vpoint = (int *) ((struct qt_var *)q)->valptr;
}
else
{
/* Var for one variable query */
if (((struct qt_var *)q)->varno != Sourcevar)
syserr("ovqpnod:src var %d,%d", ((struct qt_var *)q)->varno, Sourcevar);
s->type = VAR;
if (((struct qt_var *)q)->attno)
((struct qt_v *)s)->vpoint = (int *) (Intup + Source->reloff[((struct qt_var *)q)->attno]);
else
((struct qt_v *)s)->vpoint = (int *) &Intid;
}
}
if (s->type == AOP)
Agcount++;
/* add symbol to list */
if (Qvptr > MAXNODES - 1)
ov_err(NODOVFLOW);
Qvect[Qvptr++] = s;
}
readagg_result(result)
struct querytree *result[];
/*
**
*/
{
register struct querytree **r, *aop;
register int i;
Tend = Outtup;
r = result;
while (aop = *r++)
{
i = aop->sym.len & I1MASK;
if (aop->sym.type == CHAR)
pad(Tend, i);
bmove(Tend, aop->sym.value, i);
Tend += i;
# ifdef xDTR1
if (tTf(8, 3))
writenod(aop);
# endif
}
}
ov_err(code)
int code;
{
derror(code);
}
struct descriptor *openindex(name)
char *name;
{
register struct descriptor *d;
register int varno;
struct descriptor *readopen();
varno = SECINDVAR;
Rangev[varno].relnum = rnum_assign(name);
d = readopen(varno);
return (d);
}
/*
** Use "closer()" for closing relations. See
** desc_close in openrs.c for details.
*/
extern int closer();
int (*Des_closefunc)() = closer;
init_decomp()
{
static struct accbuf xtrabufs[12];
acc_addbuf(xtrabufs, 12);
}
startdecomp()
{
/* called at the start of each user query */
Retcode.rc_tupcount = 0;
initrange();
rnum_init();
startovqp();
}
/*
** Files_avail -- returns how many file descriptors are available
** for decomposition. For decomp combined with ovqp, the fixed
** overhead for files is:
**
** 4 -- pipes
** 1 -- relation relation
** 1 -- attribute relation
** 1 -- standard output
** 1 -- concurrency
** 1 -- indexes relation
**
** Optional overhead is:
**
** 1 -- for Equel data pipe
** 1 -- for batch file on updates
*/
files_avail(mode)
int mode;
{
register int i;
i = MAXFILES - 9;
if (Equel)
i--;
if (mode != mdRETR)
i--;
return (i);
}