# include	<ingres.h>
# include	<aux.h>
# include	<tree.h>
# include	<symbol.h>
# include	"globs.h"
# include	<sccs.h>
# include	<errors.h>

SCCSID(@(#)decomp.c	8.3	12/18/85)

/*
** DECOMP -- Process a query given a query tree and range table.
**
**	Decomp processes any arbitrary query by converting it into
**	a sequence of "one variable queries"; eg. queries involving
**	at most one source relation. This file and decision.c contain
**	the principle decision making routines.
**
**	Decomp() is called with a pointer to a query tree, the mode
**	of the query (retrieve, append, etc.), and the internal name
**	of the result relation (if any). The routines included are:
**
**	Decomp  -- Opens the source relations and decides whether the
**			query is multi-variable or single/zero variable.
**
**	Decompx -- Takes a multivariable query, removes and executes any
**			one-var restrictions and passes the remaining query
**			to decompz (if one/zero variable) or decision().
**
**	Decompy -- Performs "tuple substitution" on a multi-var query,
**			does any new one-var restrictions and passes the
**			remaining query to decompz (if one/zero variable)
**			or decision().
**
**	Decompz -- Executes a one/zero variable query by calling call_ovqp().
*/
/*
**	Process query by calling either decompx for multivar
**	or decompz for 0 or 1 var query. Decomp() must guarantee
**	that the range table is the same upon exiting as it was
**	when entered. Newquery() and endquery() perform that function.
**
**	Trace Flags:
**		30
*/

decomp(q, qmode, result_num)
QTREE	*q;
int	qmode;
int	result_num;
{
	register QTREE 	*root;
	register int 	vc, i;
	int		locrange[MAXRANGE];

	root = q;
	vc = root->sym.value.sym_root.tvarc;
#	ifdef xDTR1
	if (tTf(30, 0))
		printf("DECOMP: %d-var query, result_num=%d\n", vc, result_num);
	if (tTf(30, 1))
	{
		printf("DECOMP\n");
		treepr(root);
	}
#	endif

	openrs(root);

	if (vc > 1)
	{
		newquery(locrange);
		i = decompx(root, qmode, result_num);
		endquery(locrange, FALSE);	/* don't reopen previous range */
	}
	else
	{
		De.de_newq = 1;
		De.de_sourcevar = -1;
		i = decompz(root, qmode, result_num);
	}
	
 	/*
	** remove the range variables that the view subsystem
	** might have placed in.
	*/
	clrrange();

	return (i);
}
/*
** Decompx -- Initialize for multi-variable query.
**	All one-variable subqueries are run.
**	If the remaining query is still multi-var
**	then decision() is called; else decompz()
**	is called. The range table is restored
**	after the query is complete.
**	The tempvars from the exec_sq() are left on the
**	tree since it is presumed that the tree will be discarded
**	anyway.
**
**	Trace Flags:
**		31
*/

decompx(root, qmode, result_num)
QTREE	*root;
int	qmode;
int	result_num;
{
	register int 	i, vc;
	int		disj;
	int  		sqbuf[1+SQSIZ/sizeof(int)];
	QTREE 		*sqlist[MAXRANGE];
	int		locrang[MAXRANGE], sqrange[MAXRANGE];
	extern int	derror();

	vc = root->sym.value.sym_root.tvarc;
	initbuf((char *)sqbuf, SQSIZ, SQBUFFULL, derror);
	pull_sq(root, sqlist, locrang, sqrange, (char *)sqbuf);
	if ((i = exec_sq(sqlist, sqrange, &disj)) != -1) 
	{
		undo_sq(sqlist, locrang, sqrange, i, i, FALSE);
		return (FALSE);
	}
	vc -= disj;
	tempvar(root, sqlist, (char *)sqbuf);
	if (pull_const(root, (char *)sqbuf) == 0)
		return (FALSE);
	if (vc <= 1)
	{
		De.de_sourcevar = -1;
		De.de_newq = 1;
		return (decompz(root, qmode, result_num));
	}
	i = decision(root, qmode, result_num, (char *)sqbuf);
	undo_sq(sqlist, locrang, sqrange, MAXRANGE, MAXRANGE, FALSE);
	return (i);
}
/*
** Decompy -- decompose a multi-variable query by tuple substitution.
**	First a variable is selected
**	for substitution. Then for each tuple in the
**	selected variable, all one variable restrictions
**	are done (exec_sq) and the remaining query is
**	solved by calling either decompz() or recursively
**	decision().
**
**	The original tree and range table are guaranteed to
**	be the same on entry and exit (modulo the effects of
**	reformat()).
**
**	Trace Flags:
**		32
*/

decompy(q, qmode, result_num, sqbuf)
QTREE 	*q;
int	qmode;
int	result_num;
char	*sqbuf;
{
	register QTREE	*root;
	register int	j, vc;
	DESC		*d;
	QTREE		*newroot;
	int		constl, sqcnt, var, srcvar, maxsqcnt;
	int		disj, tc, qtrue;
	TID		tid, hitid;
	char		*tuple;
	QTREE		*sqlist[MAXRANGE];
	int		sqmark, sqmark1;
	int		locrang[MAXRANGE], sqrange[MAXRANGE];
	extern DESC	*readopen();
	extern char	*need(), *rangename();
	extern QTREE	*copy_ands();

	root = q;
	vc = root->sym.value.sym_root.tvarc;

#	ifdef xDTR1
	if (tTf(32, -1))
		printf("DECOMPY:%x,vc=%d\n", root, vc);
#	endif

	sqmark = markbuf(sqbuf);
	constl = !root->sym.value.sym_root.lvarc;
	qtrue = FALSE;

	if ((var = selectv(root)) < 0)
		return (qtrue);
	d = readopen(var);	/* gets full descriptor for setvar & get */
	tuple = need(sqbuf, d->reldum.relwid);
	setvar(root, var, &tid, tuple);
	pull_sq(root, sqlist, locrang, sqrange, sqbuf);
	tempvar(root, sqlist, sqbuf);
	reformat(var, sqlist, locrang, sqbuf, root);
	vc--;
# ifdef xDTR2
	if (tTf(32, 0))
	{
		printf("DECOMPY: &tup=%x, ", tuple);
		printdesc(d);
	}
# endif xDTR2

	/* HERE FOR MULTI-VAR SUBSTITUTION */
	sqmark1 = markbuf(sqbuf);
	De.de_newq = 1;
	tc = 0;
	sqcnt = maxsqcnt = 0;
	srcvar = -1;
	De.de_sourcevar = -1;
	find(readopen(var), NOKEY, &tid, &hitid);
	while (!(j=get(readopen(var), &tid, &hitid, tuple, NXTTUP)))
	{
#		ifdef xDTR1
		if (tTf(32, 2))
		{
			printf("Subst:");
			printup(readopen(var), tuple);
		}
#		endif
		tc++;
		if (vc > 1)
		{
			reset_sq(sqlist, locrang, sqcnt);
			if ((sqcnt = exec_sq(sqlist, sqrange, &disj)) != -1) 
				continue;

			maxsqcnt = sqcnt;
			vc -= disj;
			if (vc <= 1)
			{
				De.de_sourcevar = srcvar;
				qtrue |= decompz(root, qmode, result_num);
				srcvar = De.de_sourcevar;
			}
			else
			{
				freebuf(sqbuf, sqmark1);
				newroot = copy_ands(root, sqbuf);
				qtrue |= decision(newroot, qmode, result_num, sqbuf);
			}
			vc += disj;
		}
		else
			qtrue |= decompz(root, qmode, result_num);

		/* check for early termination on constant Target list */
		if (constl && qtrue) 
			break;
	}
	if (j < 0) 
		syserr("decompy: bad get %d on %.12s", j, readopen(var)->reldum.relid);

	/* undo the effect of pulling the sub queries */
	origvar(root, sqlist);
	undo_sq(sqlist, locrang, sqrange, sqcnt, maxsqcnt, TRUE);

	/* undo the setvar on the main tree and all subtrees */
	clearvar(root, var);
	for (j = 0; j < MAXRANGE; j++)
		clearvar(sqlist[j], var);

	/* return any used buffer space */
	freebuf(sqbuf, sqmark);

#	ifdef xDTR1
	if (tTf(32, 2))
		printf("tc[%.12s]=%d,qtrue=%d\n", rangename(var), tc, qtrue);
#	endif

	return (qtrue);
}
/*
**	Decompz processes a one variable query
**	by calling call_ovqp().
**
**	Trace Flags:
**		33
*/

decompz(q, qmode, result_num)
QTREE 	*q;
int	qmode;
int	result_num;
{
	register QTREE	*root;
	register int	qualfound;

	root = q;
	if (root->sym.value.sym_root.tvarc)
	{
		if (De.de_sourcevar < 0)
		{
			if ((De.de_sourcevar = selectv(root)) < 0) 
				return (FALSE);
		}
	}
	else
	{
		De.de_sourcevar = -1;
	}

	qualfound = call_ovqp(root, qmode, result_num);
	De.de_newq = 0;
	return (qualfound);
}
