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

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

/*
**	Reduction -- This file contains routines related to the
**	reduction algorithm. The routines are all called by
**	decision().
**
**	Included are:
**
**		algorithm -- groups clauses according to common variables
**
**		buildlist -- build linked list of clauses from a query tree
**
**		construct -- build query trees from link lists of clauses
**
**		order     -- order a linked list of clauses into the prefered
**				execution sequence
*/
/*
**	Algorithm - determine whether query is connected or not
**
**	Algorithm takes a linked list of query components
**	and groups them according to the variables involved
**	in each component. If the query is fully interconnected
**	then algorithm returns TRUE else it returns FALSE.
**
**	By definition a constant clause (one involving zero variables)
**	is considered to use all variables. Without this rule,
**	a query with a null target list would always break into
**	two pieces.
**
**	Whether a query is fully connected is independent
**	of whether there are any one variable components
**	or not. This includes the target list. After applying
**	the algorithm, a scan is made to see how many multi-var
**	components are present. If there are two or more multi-var
**	components then the query is disconnected.
**
**	Trace Flags:
**		38
*/

algorithm(clist, varmap)
struct complist	*clist;
int		varmap;
{
	register struct complist	*chead, *cnext;
	register int			var;
	int				vmap;
	struct complist			*cprev, *cl;

	vmap = varmap;
	for (var = 1; vmap; var <<= 1)
	{
		if ((vmap & var) == 0)
			continue;
		vmap &= ~var;	/* remove var */

		/* done if query is already a single piece */
		if (clist->nextcomp == 0)
			break;

		/* find first component using variable var */
		for (chead = clist; chead; chead = chead->nextcomp)
		{
			if (chead->bitmap == 0 || (chead->bitmap & var))
			{
				/* this component uses variable var */

				cprev = chead;
		
				/* look for other components using variable var */
				for (cnext = chead->nextcomp; cnext; cnext = cnext->nextcomp)
				{
					if (cnext->bitmap == 0 || (cnext->bitmap & var))
					{
		
						/*
						** Found a component. Remove it from "next"
						** link and put it with head piece
						*/
		
						/* remove piece */
						cprev->nextcomp = cnext->nextcomp;
		
						/* fix up bit map */
						chead->bitmap |= cnext->bitmap;
		
						/* find end of head component */
						for (cl = chead; cl->linkcomp; cl = cl->linkcomp);
		
						/* connect with head piece */
						cl->linkcomp = cnext;
					}
					else
						cprev = cnext;
				}
			}
		}
	}

	/* return whether connected or not connected */
	for (var =0, chead = clist; chead; chead = chead->nextcomp)
		if (bitcnt(chead->bitmap) > 1)
			var++; /* this component involves 2 or more vars */

	return (var < 2); /* return TRUE if zero or one component multi-var */
}
/*
**	Buildlist -- Build a component list from a query tree.
**
**	Each ROOT and AND node is treated as a separate component
**	and a linked list is built connecting them. The ROOT node
**	MUST be the first element. This list will later be manipulated
**	by algorithm() to determine the structure of the query.
**
**	Returns:
**		Head of the list
*/

struct complist *
buildlist(root1, buf)
QTREE	*root1;
char	*buf;
{
	register struct complist	*head, *next;
	register QTREE			*root;
	struct complist			*ret;
	extern char			*need();

	ret = (struct complist *) need(buf, 0);
	head = 0;

	for (root = root1; root->sym.type != QLEND; root = root->right)
	{
		next = (struct complist *) need(buf, sizeof (*next));
		next->clause = root;
		next->nextcomp = next->linkcomp = 0;
		next->bitmap = root->sym.value.sym_root.lvarm;

		if (head)
			head->nextcomp = next;
		head = next;
	}
	return (ret);
}
/*
**  Construct -- construct a tree from a list component
**
**	Construct takes a list head and builds a querytree
**	from the components in the list. If the head component
**	is the ROOT of the original query, then
**	the original ROOT node is reused.
**
*/

QTREE *
construct(root, listhead, buf)
QTREE		*root;
struct complist	*listhead;
char		*buf;
{
	register QTREE			*ret, *q;
	register struct complist	*clist;
	extern QTREE			*makroot();

	clist = listhead;

	/* determine ROOT of tree */
	if (root == clist->clause)
	{
		q = root;
		clist = clist->linkcomp;
	}
	else
	{
		q = makroot(buf);
	}
	ret = q;
	for (; clist; clist = clist->linkcomp)
	{
		q->right = clist->clause;
		q = q->right;
	}

	q->right = De.de_qle;

	mapvar(ret, 1);
#	ifdef xDTR1
	if (tTf(38, 0))
	{
		printf("Construct\n");
		treepr(ret);
	}
#	endif
	return (ret);
}
/*
**  Order -- order a link list set of query components.
**
**	Takes a list of components and orders them:
**		first - disjoint components
**		second - reduction pieces
**		last - the original target list piece
**
**	Return:
**		new head of list
*/

struct complist *
order(clist, ovlapvar)
struct complist	*clist;
int		ovlapvar;
{
	register struct complist	*cl, *joint, *disjoint;
	struct complist			*xd, *xj, *tlpiece, *ret;
	QTREE				*tmp;
	int				map;

	tlpiece = clist;	/* target list piece always first */
	disjoint = joint = 0;
	map = ovlapvar >= 0 ? 1 << ovlapvar : 0;

	/* examine each irreducible component for disjointness */
	for (cl = tlpiece->nextcomp; cl; cl = cl->nextcomp)
	{
		if (cl->bitmap & map)
		{
			/* joint piece */
			if (joint == 0)
			{
				joint = cl;
				xj = cl;
			}
			else
			{
				joint->nextcomp = cl;
				joint = cl;
			}
		}
		else
		{
			/* disjoint piece */
			if (disjoint == 0)
			{
				disjoint = cl;
				xd = cl;
			}
			else
			{
				disjoint->nextcomp = cl;
				disjoint = cl;
			}
		}

	}
	/* we now have all disjoint, joint and tl pieces */
	/* order them in order (1) xd, (2) xj, (3) tlpiece */

	ret = tlpiece;
	tlpiece->nextcomp = 0;

	if (joint)
	{
		ret = xj;
		joint->nextcomp = tlpiece;
		if ((tlpiece->bitmap & (~map)) == 0)
		{
			/*
			** This is the special case of the target list
			** being one (or zero) variable and that variable
			** is the overlap variable. If left as is, the
			** reduction will take one step more than is
			** necessary. The target list piece is combined
			** with the last joint piece and processed together.
			**
			** An example of when this will happen is:
			** ret(p.a) : p.b = s.b ^ p.c = y.c
			**
			** Reduction would split this up into
			** (1) ret (p.a,p.b) : p.c = y.c
			** (2) ret (p.a) : p.b = s.b
			** (3) ret (p.a)
			**
			** Here we are allowing pieces (2) & (3) to be done together
			*/

			for (cl = joint; cl->linkcomp; cl = cl->linkcomp);

			cl->linkcomp = tlpiece;
			joint->nextcomp = 0;

			/* switch tl clause to top of complist */
			tmp = joint->clause;
			joint->clause = tlpiece->clause;
			tlpiece->clause = tmp;
		}
	}

	if (disjoint)
	{
		ret = xd;
		disjoint->nextcomp = joint ? xj : tlpiece;
	}

	return (ret);
}
