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

SCCSID(@(#)pull_sq.c	8.1	12/31/84)

/*
** DECOMP1.C
**
**	contains routines associated with setting up 
**	detachable 1-variable sub-queries.
**	ptrs to these sq's are kept in the 
**	array 'sqlist' declared in the main decomp routine.
**
**	Trace Flags:
**		34
*/


pull_sq(tree1, sqlist, locrang, sqrange, buf)
QTREE	*tree1;
QTREE	*sqlist[];
int	locrang[];
int	sqrange[];
char	*buf;
{
	register QTREE 	*q, *tree, *r;
	QTREE 		*s;
	int 		anysq, j, badvar;
	extern QTREE	*makroot();

	tree = tree1;

#	ifdef xDTR1
	if (tTf(34, 0))
		printf("PULL_SQ:tree=%x\n", tree);
#	endif

	anysq = 0;
	for (j = 0; j < MAXRANGE; j++)
		sqlist[j] = 0;

	if (tree->sym.value.sym_root.tvarc == 1)
		return;

	/* detach all one variable clauses except:
	** if the target list is one variable and
	** that variable is disjoint from the other
	** variables, then don't pull it.
	**
	** It will be more efficient to process it
	** all at once in decompy
	*/

	badvar = 0;
	if (tree->sym.value.sym_root.lvarc == 1)
	{
		badvar = tree->sym.value.sym_root.lvarm;	/* get bit position of var */

		/* look for a two variable clause involving badvar */
		for (r = tree->right; r->sym.type != QLEND; r = r->right)
		{
			if (r->sym.value.sym_root.lvarc > 1 && (r->sym.value.sym_root.lvarm & badvar))
			{
				badvar = 0;
				break;
			}
		}
	}
#	ifdef xDTR1
	if (tTf(34, 2))
		printf("Detachable clauses: (badvar=%o)\n", badvar);
#	endif
	for (r=tree; r->right->sym.type!=QLEND; )
	{
#		ifdef xDTR1
		if (tTf(34, 3))
			nodepr(r);
#		endif
		q = r;
		r = r->right;
		if (r->sym.value.sym_root.lvarc == 1)
		{
			j = bitpos(r->sym.value.sym_root.lvarm);
#			ifdef xDTR1
			if (tTf(34, 4))
			{
				printf("\nvar=%d, clause\n", j);
				treepr(r->left);
			}
#			endif
			if (r->sym.value.sym_root.lvarm == badvar)
			{
#				ifdef xDTR1
				if (tTf(34, 5))
					printf("not detaching \n");
#				endif
				continue;
			}
			anysq++;

			if (!sqlist[j])		/* MAKE ROOT NODE FOR SUBQUERY */
				sqlist[j] = makroot(buf);
			s = sqlist[j];

			/* MODIFY MAIN QUERY */

			q->right = r->right;

			/* MODIFY `AND` NODE OF DETACHED CLAUSE */

			r->right = s->right;
			r->sym.value.sym_root.rvarm = s->sym.value.sym_root.rvarm;
			r->sym.value.sym_root.tvarc = 1;

			/* ADD CLAUSE TO SUB-QUERY */

			s->right = r;
			s->sym.value.sym_root.rvarm = r->sym.value.sym_root.lvarm;
			s->sym.value.sym_root.tvarc = 1;

#			ifdef xDTR1
			if (tTf(34, 6))
			{
				printf("SQ\n");
				treepr(s);
			}
#			endif

			r = q;
		}
	}

	/* NOW SET UP TARGET LIST FOR EACH SUBQUERY IN SQLIST */

#	ifdef xDTR1
	if (tTf(34, 7))
		printf("# sq clauses=%d\n", anysq);
#	endif
	if (anysq)
	{
#		ifdef xDTR1
		if (tTf(34, 8))
			printf("Dfind--\n");
#		endif
		dfind(tree, buf, sqlist);
		mapvar(tree, 1);

		/* create the result relations */
		for (j = 0; j < MAXRANGE; j++)
		{
			if (q = sqlist[j])
			{
				if (q->left->sym.type != TREE)
				{
					savrang(locrang, j);
					sqrange[j] = mak_t_rel(q, "d", -1);
				}
				else
					sqrange[j] = NORESULT;
			}
		}
	}
}
/*
**  DFIND
*/
dfind(tree, buf, sqlist)
register QTREE	*tree;
char		*buf;
QTREE		*sqlist[];
{
	register char	varno;
	register QTREE	*sq;
	extern QTREE	*ckvar();

	if (tree == NULL) 
		return;
#	ifdef xDTR1
	if (tTf(34, 9))
		nodepr(tree);
#	endif
	if (tree->sym.type == VAR)
	{
		tree = ckvar(tree);
		varno = tree->sym.value.sym_var.varno;
		if (sq = sqlist[varno])
			maktl(tree, buf, sq, varno);
		return;
	}

	/* IF CURRENT NODE NOT A `VAR` WITH SQ, RECURSE THRU REST OF TREE */

	dfind(tree->left, buf, sqlist);
	dfind(tree->right, buf, sqlist);
	return;
}
/*
**  MAKTL
*/

maktl(node, buf, sq1, varno)
QTREE	*node;
char	*buf;
QTREE	*sq1;
int	varno;
{
	register QTREE 	*resdom, *tree, *sq;
	int		domno, map;
	extern QTREE	*makresdom();
	extern QTREE	*copytree();

	sq = sq1;
	domno = node->sym.value.sym_var.attno;

#	ifdef xDTR1
	if (tTf(34, 12))
		printf("\tVar=%d,Dom=%d ", varno, domno);
#	endif
	/* CHECK IF NODE ALREADY CREATED FOR THIS DOMAIN */

	for (tree = sq->left; tree->sym.type != TREE; tree = tree->left)
		if (tree->right->sym.value.sym_var.attno == domno)
		{
#			ifdef xDTR1
			if (tTf(34, 13))
				printf("Domain found\n");
#			endif
			return;
		}

	/* create a new resdom for domain */

	resdom = makresdom(buf, node);
	resdom->sym.value.sym_resdom.resno = sq->left->sym.type == TREE? 1:
					sq->left->sym.value.sym_resdom.resno + 1;
	/* resdom->right is a copy of the var node in order to
	** protect against tempvar() changing the var node.
	*/
	resdom->left = sq->left;
	resdom->right = copytree(node, buf);


	/* update ROOT node if necessary */

	sq->left = resdom;
	map = 1 << varno;
	if (!(sq->sym.value.sym_root.lvarm & map))
	{
		/* var not currently in tl */
		sq->sym.value.sym_root.lvarm |= map;
		sq->sym.value.sym_root.lvarc++;

		/* if var is not in qualification then update total count */
		if (!(sq->sym.value.sym_root.rvarm & map))
			sq->sym.value.sym_root.tvarc++;
#		ifdef xDTR1
		if (tTf(34, 15))
		{
			printf("new root ");
			nodepr(sq);
		}
#		endif
	}

#	ifdef xDTR1
	if (tTf(34, 14))
	{
		printf("new dom ");
		nodepr(resdom);
	}
#	endif
	return;
}
