# include	<pv.h>
# include	<ingres.h>
# include	<access.h>
# include	<aux.h>
# include	<catalog.h>
# include	<symbol.h>
# include	<func.h>
# include	<sccs.h>
# include	<errors.h>

SCCSID(@(#)rmqm.c	8.3	2/8/85)

/*
**  RMQM -- DBU to delete protection and integrity constraints
**
**	Trace Flags:
**		43
*/


extern	short	tTdbu[];
extern	int	dest_const();
extern	void	null_fn();

struct fn_def RmqmFn =
{
	"RMQM",
	dest_const,
	null_fn,
	null_fn,
	NULL,
	0,
	tTdbu,
	100,
	'Z',
	0
};
/*
**  DEST_CONST -- destroy constraints
**
**	Parameters:
**		pc -- number of parameters in pv
**		pv -- pv [0] == DESTPROT destroy permission
**			         == DESTINTEG destroy integrity constraint
**		        pv [1]    relation from which to destroy constraint
**		        pv [2] == if (pc != 2) relation from which to delete
**				     	constraints
**		        pv[3] ... pv[pc - 1] == id of constraint
**
**	Returns:
**		0
**
**	Side Effects:
**		destroys constraints. Involves activity on catalogs 'relation',
**		protect, integrities, and tree.
**
**	Trace Flags:
**		43, 0
*/

dest_const(pc, pv)
int	pc;
PARM	pv[];
{
	DESC			d;
	register int		i;
	int			mode;
	extern struct admin	Admin;

#	ifdef xZTR1
	if (tTf(43, 0))
	{
		printf("dest_const: ");
		prvect(pc, pv);
	}
#	endif

	if (!(Admin.adhdr.adflags & A_QRYMOD))
		return (0);
	i = openr(&d, OR_RELTID, pv[1].pv_val.pv_str);
	if (i < 0)
		syserr("dest_const: openr(%s) %d", pv[1].pv_val.pv_str, i);

	if (i == 1 || !bequal(Usercode, d.reldum.relowner, UCODE_SZ))
	{
		error(RELNOEXIST, pv[1].pv_val.pv_str, 0);
		return (0);
	}

	mode = atoi(pv[0].pv_val.pv_str);
	if (mode == DESTPROT)
		dest_prot(&d, &pv[2]);
	else if (mode == DESTINTEG)
		dest_integ(&d, &pv[2]);
	else
		syserr("dest_const: bad mode %d", mode);
	return (0);
}
/*
**  DEST_INTEG -- directs destruction of integrity constraints
**
**	Parameters:
**		desc -- descriptor for relation
**		intv -- PV_EOF terminated list of id strings, if first element
**		        is PV_EOF means "all"
**
**	Returns:
**		none
**
**	Side Effects:
**		deletes integrity constraint. Activity on 'relation', integrities,
**		and tree.
*/

dest_integ(d, intv)
register DESC	*d;
PARM		intv[];
{
	extern DESC		Intdes;
	struct integrity	tuple, key;
	struct tree		tkey;
	register		i, j;
	int			tree_const();
	int			int_inttree();

#	ifdef xZTR1
	if (tTf(43, 1))
		printf("dest_integ((%s, %s)...)\n", d->reldum.relid, d->reldum.relowner);
#	endif

	i_cat("integrities", &Intdes, &key, d->reldum.relid, INTRELID,
	d->reldum.relowner, INTRELOWNER, mdINTEG, &tkey);

	if (intv[0].pv_type == PV_EOF)
	{
		/* destroy integrity 'relation' ALL */
		if (!(d->reldum.relstat & S_INTEG))
			return (0);
		del_all(d, &Intdes, &key, &tuple, &tkey, S_INTEG,
		tree_const, int_inttree);
		return (0);
	}
	/* destroy integrity 'relation' int {, int} */
	for (i = 0; intv[i].pv_type != PV_EOF; i++)
		del_int(&Intdes, &key, &tuple, &tkey, intv[i].pv_val.pv_str, INTTREE, 
		tree_const, int_inttree);

	/* rescan to output error messages */
	for (j = 0; j < i; j++)
		if (*(intv[j].pv_val.pv_str))
			error(BADINTEG, intv[j].pv_val.pv_str, 0);

	/* finally, check that there are still integrity constraints
	** on the relation, if not must reset the S_INTEG bit in the relation
	** relation tuple for that relation.
	*/
	chk_const(d, &Intdes, &key, &tuple, d->reldum.relid, INTRELID, d->reldum.relowner,
	INTRELOWNER, S_INTEG);
}
/*
**  DEST_PROT -- directs destruction of protection constraints
**
**	Parameters:
**		desc -- descriptor for relation
**		intv -- PV_EOF terminated list of id strings, if first element
**		        is PV_EOF means "all"
**
**	Returns:
**		none
**
**	Side Effects:
**		deletes protection constraint. Activity on 'relation', 
**		protect, and tree.
**
**	Trace Flags:
**		43, 2
*/


dest_prot(d, intv)
register DESC	*d;
PARM		intv[];
{
	extern DESC	Prodes;
	struct protect	tuple, key;
	struct tree	tkey;
	register	i, j;
	int		propermid;
	int		prot_protree();
	int		tree_prot();

#	ifdef xZTR1
	if (tTf(43, 2))
		printf("dest_prot((%s, %s)...)\n", d->reldum.relid, d->reldum.relowner);
#	endif

	i_cat("protect", &Prodes, &key, d->reldum.relid, PRORELID, d->reldum.relowner,
	PRORELOWN, mdPROT, &tkey);

	if (intv[0].pv_type == PV_EOF)
	{
		/* destroy permit 'relation' ALL */
		if (!(d->reldum.relstat & S_PROTRET) || !(d->reldum.relstat & S_PROTALL))
			r_relstat(d, S_PROTRET | S_PROTALL, 1);
		if (!(d->reldum.relstat & S_PROTUPS))
			return (0);
		del_all(d, &Prodes, &key, &tuple, &tkey, S_PROTUPS,
		tree_prot, prot_protree);
		return (0);
	}
	/* destroy permit 'relation' int {, int} */
	for (i = 0; intv[i].pv_type != PV_EOF; i++)
	{
		propermid = atoi(intv[i].pv_val.pv_str);
		if (propermid == 0)
		{
			if (!(d->reldum.relstat & S_PROTALL))
			{
				r_relstat(d, S_PROTALL, 1);
				intv[i].pv_val.pv_str = 0;
			}
			continue;
		}
		else if (propermid == 1)
		{
			if (!(d->reldum.relstat & S_PROTRET))
			{
				r_relstat(d, S_PROTRET, 1);
				intv[i].pv_val.pv_str = 0;
			}
			continue;
		}
		del_int(&Prodes, &key, &tuple, &tkey, intv[i].pv_val.pv_str, PROPERMID, 
		tree_prot, prot_protree);
	}
	/* rescan to output error messages */
	for (j = 0; j < i; j++)
		if (intv[j].pv_val.pv_str && intv[j].pv_val.pv_str[0] )
			error(BADPROT, intv[j].pv_val.pv_str, 0);

	/* finally, check that there are still permissions
	** on the relation, if not must reset the S_PROTUPS bit in the relation
	** relation tuple for that relation's relstat.
	*/
	chk_const(d, &Prodes, &key, &tuple, d->reldum.relid, PRORELID,
	d->reldum.relowner, PRORELOWN, S_PROTUPS);
}
/*
**  I_CAT -- prepare catalogs for deletin of constraint
**
**	Initializes treerelid, treeowner, and treetype fields
**	of tree key. Also relation id and owner fields of
**	appropriate catalog c_desc, with key 'key'.
**
**	Parameters:
**		c_name -- name of catalog for opencatalog
**		c_desc -- descriptor of catalog
**		key -- key for catalog
**		relid -- relation.relid for relation to be de-constrained
**		id_attno -- attno of relid in constraint catalog c_desc
**		relowner -- relation.relowner for rel to be de-constrained
**		own_attno -- attno of owner in constrain catalog
**		type -- treetype for tree tuple (depends on catalog)
**		tkey -- key for tree catalog
**
**	Returns:
**		none
**
**	Side Effects:
**		opencatalogs the constraint catalog c_desc, and the "tree" rel
**		for READ/WRITE. Sets keys.
**
**	Trace Flags:
**		43, 3
*/

i_cat(c_name, c_desc, key, relid, id_attno, relowner, own_attno, type, tkey)
char		*c_name;
DESC		*c_desc;
char		*key;
char		*relid;
int		id_attno;
char		*relowner;
int		own_attno;
int		type;
struct tree	*tkey;
{
	extern DESC	Treedes;
	char		realtype;

#	ifdef xZTR1
	if (tTf(43, 3))
		printf("i_cat(c_name \"%s\", relid %s id_attno %d relowner %s own_attno %d type %d)\n",
		c_name, relid, id_attno, relowner, own_attno, type);
#	endif

	realtype = type;
	opencatalog("tree", OR_WRITE);
	setkey(&Treedes, tkey, relid, TREERELID);
	setkey(&Treedes, tkey, relowner, TREEOWNER);
	setkey(&Treedes, tkey, &realtype, TREETYPE);
	opencatalog(c_name, OR_WRITE);
	clearkeys(c_desc);
	setkey(c_desc, key, relid, id_attno);
	setkey(c_desc, key, relowner, own_attno);
}
/*
**  DEL_ALL -- delete all constraints for a given relation
**
**	Deletes all constraints of a given type given by a constraint
**	catalog 'c_desc'. Note that Protection constraints 0 & 1, given
**	by relation.relstat field are not deleted here.
**
**	Parameters:
**		r_desc -- descriptor for relation to de-constrain (for
**			r_relstat)
**		c_desc -- constraint catalog descriptor
**		key -- c_desc's key
**		tuple -- c_desc's tuple (needed because sizeof tuple is not
**			known here, so must be allocated beforehand)
**		tkey -- tree key with TREERELID and TREERELOWNER setkeyed
**		bit -- bits in relstat to reset after deleting all constraints
**		tree_pred -- called with constraint tuple to determine
**			wether a tree tuple is present or not (as can happen
**			for protect catalog)
**		tree_field -- should return the treeid from tuple
**
**	Returns:
**		none
**
**	Side Effects:
**		tree and constraint catalog activity
**
**	Requires:
**		del_tree()
**		r_relstat()
**
**	Called By:
**		dest_????
**
**	Trace Flags:
**		43, 4
**
**	Syserrs:
**		bad find, get, delete, flush_rel
**
**	History:
**		1/10/79 -- (marc) written
*/

del_all(r_desc, c_desc, key, tuple, tkey, bit, tree_pred, tree_field)
DESC		*r_desc;
DESC		*c_desc;
char		*key;
char		*tuple;
struct tree	*tkey;
int		bit;
int		(*tree_pred)();
int		(*tree_field)();
{
	TID		lotid, hitid;
	register int	i;

#	ifdef xZTR1
	if (tTf(43, 4))
		printf("del_all(bit=0%o)\n", bit);
#	endif

	if (i = find(c_desc, EXACTKEY, &lotid, &hitid, key))
		syserr("del_all: find %d", i);
	while (!(i = get(c_desc, &lotid, &hitid, tuple, TRUE)))
	{
		if (!kcompare(c_desc, tuple, key))
		{
			/* for each constraint of for a relation */
			if (i = delete(c_desc, &lotid))
				syserr("del_all: delete %d", i);
			/* for crash recovery */
			if (i = flush_rel(c_desc, FALSE))
				syserr("del_all: flush_rel %d", i);
			/* if there is a tree tuple, destroy it */
			if ((*tree_pred)(tuple))
				del_tree(tkey, (*tree_field)(tuple));
		}
	}
	if (i != 1)
		syserr("del_all: get %d", i);
	/* turn off bit in relstat field */
	r_relstat(r_desc, bit, 0);
}
/*
**  DEL_INT -- delete from a constraint catalog a constraint
**
**	Parameters:
**		c_desc -- catalog descriptor
**		key -- catalog key
**		tuple -- catalog tuple (needed because tuple size unknown here)
**		tkey -- tree key with TREERELID and TREERELOWNER setkeyed
**		constid -- integer constraint id in string form
**		constattno -- attno of comstraint number in c_desc
**		tree_pred -- predicate on existence of tree tuple 
**		tree_field -- returns treeid from constrain tuple
**
**	Returns:
**		none
**
**	Side Effects:
**		constraint and tree catalog activity.
**		*constid set to 0 if constraint id exists.
**
**	Requires:
**		del_tree()
**
**	Called By:
**		dest_????
**
**	Trace Flags:
**		43, 5
**
**	Syserrs:
**		bad atoi (parser error), getequal, delete, flush_rel
**
**	History:
**		1/10/79 -- (marc) written
*/

del_int(c_desc, key, tuple, tkey, constid, constattno, tree_pred, tree_field)
DESC		*c_desc;
char		*key;
char		*tuple;
struct tree	*tkey;
char		*constid;
int		constattno;
int		(*tree_pred)();
int		(*tree_field)();
{
	TID		tid;
	register int	i;
	short		constnum;

#	ifdef xZTR1
	if (tTf(43, 5))
		printf("del_int(constid=%s, constattno=%d)\n", 
	 	constid, constattno);
#	endif

	constnum = atoi(constid);
	setkey(c_desc, key, &constnum, constattno);
	if (!(i = getequal(c_desc, key, tuple, &tid)))
	{
		if (i = delete(c_desc, &tid))
			syserr("del_int(%d) %d", constid, i);
		if ((*tree_pred)(tuple))
			del_tree(tkey, (*tree_field)(tuple));
		*constid = '\0';
		return;
	}
	else if (i != 1)
		syserr("dest_int: getequal %d", i);
	/* bad constnum */
}
/*
**  DEST_TREE -- destroy a tree tuple with for a given treeid
**
**	Deletes all tuples from tree with 'treeid' and previously set
**	keys.
**
**	Parameters:
**		key -- tre key
**		treeid -- integer treeid
**
**	Returns:
**		none
**
**	Side Effects:
**		tree activity
**
**	Trace Flags:
**		43, 6
*/

del_tree(key, treeid)
struct tree	*key;
int		treeid;
{
	struct tree	tuple;
	TID		lotid, hitid;
	register int	i;
	register int	flag;
	short		realid;
	extern DESC	Treedes;

#	ifdef xZTR1
	if (tTf(43, 6))
		printf("del_tree(treeid=%d)\n", treeid);
#	endif

	realid = treeid;
	setkey(&Treedes, key, &realid, TREEID);
	if (i = find(&Treedes, EXACTKEY, &lotid, &hitid, key))
		syserr("del_tree: bad find %d treeid %d", i, treeid);
	flag = 0;
	while (!(i = get(&Treedes, &lotid, &hitid, &tuple, TRUE)))
	{
		if (!kcompare(&Treedes, &tuple, key))
		{
			if (i = delete(&Treedes, &lotid))
				syserr("del_tree: delete treeid %d %d", treeid, i);
			if (!flag)
				flag++;
		}
	}
	if (i != 1)
		syserr("del_tree: bad get %d", i);
	if (!flag)
		syserr("del_tree: no tuples qualified treeid %d", treeid);
	if (i = flush_rel(&Treedes, FALSE))
		syserr("del_tree: flush_rel(&Treedes) %d", i);
}
/*
**  CHK_CONST -- check constraint catlg for tuples for a rel, and reset relatin.relstat
**
**	Parameters:
**		r_desc -- reon desc for de-constrained relation
**		c_desc -- catalog desc
**		key -- catalog key (here unknown size)
**		tuple -- " tuple space " " " " "
**		relid -- relation name
**		id_attno -- attno of relid
**		relowner -- relation owner
**		own_attno -- relowner attno
**		bit -- bits to reset in relstat if there are no constraints left
**
**	Returns:
**		none
**
**	Side Effects:
**		reads catalog, maybe changes relstat field of relation
**		relations's r_desc tuple
**
**	Trace Flags:
**		43, 7
*/

chk_const(r_desc, c_desc, key, tuple, relid, id_attno, relowner, own_attno, bit)
DESC	*r_desc;
DESC	*c_desc;
char	*key;
char	*tuple;
char	*relid;
int	id_attno;
char	*relowner;
int	own_attno;
int	bit;
{
	TID		tid;
	register int	i;


#	ifdef xZTR1
	if (tTf(43, 7))
		printf("chk_const: relid %s id_attno %d relowner %s own_attno %d bit 0%o)\n",
		relid, id_attno, relowner, own_attno, bit);
#	endif

	clearkeys(c_desc);
	setkey(c_desc, key, relid, id_attno);
	setkey(c_desc, key, relowner, own_attno);
	if ((i = getequal(c_desc, key, tuple, &tid)) == 1)
		r_relstat(r_desc, bit, 0);
	else if (i < 0)
		syserr("chk_const: getequal %d", i);
}
/*
**  R_RELSTAT -- set or reset bits in the relation.relstat field
**
**	Does the above for relation described by desc.
**
**	Parameters:
**		d -- relation to have relation.relstat field changed
**		bit -- bits to set or reset
**		action -- 0 reset, 1 set
**
**	Returns:
**		none
**
**	Side Effects:
**		relation is opened for READ/WRITE, relstat changed
**
**	Trace Flags:
**		43, 8
*/


r_relstat(d, bit, action)
register DESC	*d;
int		bit;
int		action;
{
	struct relation	tuple, key;
	TID		tid;
	register int	i;
	extern DESC	Reldes;

#	ifdef xZTR1
	if (tTf(43, 8))
		printf("r_relstat(bit=0%o, action %d)\n",
		bit, action);
#	endif

	opencatalog("relation", OR_WRITE);
	clearkeys(&Reldes);
	setkey(&Reldes, &key, d->reldum.relid, RELID);
	setkey(&Reldes, &key, d->reldum.relowner, RELOWNER);
	if (i = getequal(&Reldes, &key, &tuple, &tid))
		syserr("r_relstat: getequal %s, %s, %d", d->reldum.relid,
		d->reldum.relowner, i);
	if (action)
	{
		if (tuple.relstat == (i = tuple.relstat | bit))
			return;
		tuple.relstat = i;
	}
	else
	{
		if (tuple.relstat == (i = tuple.relstat & ~bit))
			return;
		tuple.relstat = i;
	}
	if ((i = replace(&Reldes, &tid, &tuple, 0)) < 0 || i == 2)
		syserr("r_relstat: replace %d", i);
	if (i = flush_rel(&Reldes, FALSE))
		syserr("r_relstat: flush_rel(&Reldes) %d", i);
}
/*
**  TREE_CONST -- True predicate
**
**	Called indirectly by routines wishing to know if
**	a integrity constraint has an associated tree tuple.
**	As this is always the case, returns TRUE always.
**
**	Parameters:
**		i -- integrity tuple
**
**	Returns:
**		TRUE
**
**	Side Effects:
**		none
**
**	Trace Flags:
**		43, 9
*/

tree_const(i)
struct integrity	*i;
{
#	ifdef xZTR1
	if (tTf(43, 9))
		printf("tree_const()\n");
#	endif

	return (TRUE);
}
/*
**  TREE_PROT -- Protection tuple tree predicate
**
**	Called indirectly by routines wishing to know if
**	a protection constraint has an associated tree tuple.
**
**	Parameters:
**		p -- protect tuple
**
**	Returns:
**		TRUE -- if p->protree != -1
**		FLASE -- otherwise
**
**	Side Effects:
**		none
**
**	Trace Flags:
**		43, 9
*/

tree_prot(p)
struct protect	*p;
{
#	ifdef xZTR1
	if (tTf(43, 9))
		printf("tree_prot(p->protree=%d)\n", p->protree);
#	endif

	if (p->protree == -1)
		return (FALSE);
	else
		return (TRUE);
}
/*
**  PROT_PROTREE -- get protree field of a protection tuple
**
**	Parameters:
**		p -- protect tuple
**
**	Returns:
**		p->protree
**
**	Side Effects:
**		none
**
**	Trace Flags:
**		43, 9
*/

prot_protree(p)
struct protect	*p;
{
#	ifdef xZTR1
	if (tTf(43, 9))
		printf("prot_protree(protree=%d)\n", p->protree);
#	endif

	return (p->protree);
}
/*
**  INT_INTTREE -- get inttree field of a integrity tuple
**
**	Parameters:
**		i -- integrity tuple
**
**	Returns:
**		i->inttree
**
**	Side Effects:
**		none
**
**	Trace Flags:
**		43, 9
*/

int_inttree(i)
struct integrity	*i;
{
#	ifdef xZTR1
	if (tTf(43, 9))
		printf("int_inttree(inttree=%d)\n", i->inttree);
#	endif

	return (i->inttree);
}
