text: # include	"../ingres.h"
  # include	"../aux.h"
  # include	"../pipes.h"
  # include	"../catalog.h"
  # include	"../tree.h"
  # include	"../symbol.h"
  # include	"qrymod.h"
  
  
  /*
  **  D_INTEG -- define integrity constraint
  **
  **	An integrity constraint (as partially defined by the last
  **	tree defined by d_tree) is defined.
  **
  **	Parameters:
  **		none
  **
  **	Returns:
  **		none
  **
  **	Side Effects:
  **		Activity in 'relation' and 'integrities' catalogs.
  **
  **	Requires:
  **		issueinvert -- to check if the qualification is
  **			initially satisfied.
  **
  **	Called By:
  **		define
  **
  **	Trace Flags:
  **		49
  **
  **	Diagnostics:
  **		3490 -- there are aggregates in the qualification.
  **		3491 -- multivariable constraint.
  **
  **	Syserrs:
  **		On inconsistancies.
  **
  **	History:
  **		2/19/79 (eric) -- broken off from define.c.
  */
  
  extern QTREE			*Treeroot;
  extern struct descriptor	Intdes;
  extern struct descriptor	Reldes;
  extern struct pipfrmt		Pipe;
  
  
  
  d_integ()
  {
  	register int		i;
  	register QTREE		*t;		/* definition tree */
  	struct integrity	inttup;
  	struct tup_id		tid;
  	register int		rv;		/* result variable */
  	struct retcode		*rc;
  	extern struct retcode	*issueinvert();
  	struct relation		relkey;
  	struct relation		reltup;
  
  	t = Treeroot;
  	Treeroot = NULL;
  	rv = Resultvar;
  
  	/* pipe is not used, clear it out */
  	rdpipe(P_SYNC, &Pipe, R_up);
  
  	/*
  	**  Check for valid environment.
  	**	The tree must exist, have a qualification, and have
  	**	no target list.  The query mode must be mdDEFINE.
  	**
  	**	User level stuff checks to see that this is single
  	**	variable aggregate free, since that's all we know
  	**	about thusfar.  Also, the relation in question must
  	**	not be a view.
  	*/
  
  #	ifdef xQTR3
  	if (t == NULL)
  		syserr("d_integ: NULL tree");
  	if ((i = t->right->sym.type) != AND)
  		syserr("d_integ: qual %d", i);
  	if ((i = t->left->sym.type) != TREE)
  		syserr("d_integ: TL %d", i);
  	if (Qmode != mdDEFINE)
  		syserr("d_integ: Qmode %d", Qmode);
  #	endif
  	
  	/* check for aggregates */
  	if (aggcheck(t))
  		ferror(3490, -1, rv, 0);	/* aggregates in qual */
  
  	/* check for multi-variable */
  	for (i = 0; i < MAXVAR + 1; i++)
  	{
  		if (!Rangev[i].rused)
  			continue;
  		if (i != rv)
  		{
  #			ifdef xQTR3
  			if (tTf(49, 1))
  				printf("d_integ: Rv %d(%.14s) i %d(%.14s)\n",
  				    rv, Rangev[rv].relid, i, Rangev[i].relid);
  #			endif
  			ferror(3491, -1, rv, 0);	/* too many vars */
  		}
  	}
  
  	/* check for the resultvariable being a real relation */
  	if ((Rangev[rv].rstat & S_VIEW) != 0)
  		ferror(3493, -1, rv, 0);	/* is a view */
  	
  	/* guarantee that you own this relation */
  	if (!bequal(Usercode, Rangev[rv].rowner, 2))
  		ferror(3494, -1, rv, 0);	/* don't own reln */
  
  	/*
  	**  Guarantee that the integrity constraint is true now.
  	**	This involves issuing a retrieve statement for the
  	**	inverse of the qualification.  The target list is
  	**	already null, so we will get nothing printed out
  	**	(only a return status).
  	*/
  
  	Qmode = mdRETR;
  	Resultvar = -1;
  
  	/* issue the invert of the query */
  	rc = issueinvert(t);
  	if (rc->rc_tupcount != 0)
  		ferror(3492, -1, rv, 0);	/* constraint not satisfied */
  
  	/*
  	**  Set up the rest of the environment.
  	*/
  
  	opencatalog("integrities", 2);
  	clr_tuple(&Intdes, &inttup);
  	Resultvar = -1;
  	Qmode = -1;
  
  	/*
  	**  Set up integrity relation tuple.
  	**	The qualification will be scanned, and a set of
  	**	domains referenced will be created.  Other stuff
  	**	is filled in from the range table and from the
  	**	parser.
  	**
  	**	The tree is actually inserted into the tree catalog
  	**	in this step.  Extra information is cleared here.
  	*/
  
  	inttup.intresvar = rv;
  	bmove(Rangev[rv].relid, inttup.intrelid, MAXNAME);
  	bmove(Rangev[rv].rowner, inttup.intrelowner, 2);
  	makeidset(rv, t, inttup.intdomset);
  	inttup.inttree = puttree(t, inttup.intrelid, inttup.intrelowner, mdINTEG);
  
  	/*
  	**  Insert tuple into integrity catalog.
  	*/
  
  	i = insert(&Intdes, &tid, &inttup, FALSE);
  	if (i < 0)
  		syserr("d_integ: insert");
  	if (noclose(&Intdes) != 0)
  		syserr("d_integ: noclose int");
  
  	/*
  	**  Update relstat S_INTEG bit.
  	*/
  
  	if ((Rangev[rv].rstat & S_INTEG) == 0)
  	{
  		opencatalog("relation", 2);
  		setkey(&Reldes, &relkey, inttup.intrelid, RELID);
  		setkey(&Reldes, &relkey, inttup.intrelowner, RELOWNER);
  		i = getequal(&Reldes, &relkey, &reltup, &tid);
  		if (i != 0)
  			syserr("d_integ: geteq");
  		reltup.relstat |= S_INTEG;
  		i = replace(&Reldes, &tid, &reltup, FALSE);
  		if (i != 0)
  			syserr("d_integ: replace");
  		if (noclose(&Reldes) != 0)
  			syserr("d_integ: noclose rel");
  	}
  }
  
  
  makeidset(varno, tree, dset)
  int	varno;
  QTREE	*tree;
  int	dset[8];
  {
  	register int	vn;
  	register QTREE	*t;
  
  	vn = varno;
  	t = tree;
  
  	while (t != NULL)
  	{
  		if (t->sym.type == VAR && ((struct qt_var *)t)->varno == vn)
  			lsetbit(((struct qt_var *)t)->attno, dset);
  		
  		/* handle left subtree recursively */
  		makeidset(vn, t->left, dset);
  
  		/* handle right subtree iteratively */
  		t = t->right;
  	}
  }
  