# include	<ingres.h>
# include	<aux.h>
# include	<symbol.h>
# include	<tree.h>
# include	<catalog.h>
# include	"../decomp/globs.h"
# include	"strategy.h"
# include	<btree.h>
# include	<sccs.h>

SCCSID(@(#)key.c	8.4	3/20/85)



/*
**	Exactkey checks to see if the relation described
**	by "ap" can be used in a hashed scan.
**	All the key domains of the relation must
**	have simple clauses of equality associated
**	with them in the qualification.
**
**	Returns 0 if the relation can't be used.
**
**	Returns > 0 if it can.
*/

exactkey(ap, key)
struct accessparam	*ap;
struct key		*key;
{
	register struct accessparam	*a;
	register struct key		*k;
	register struct simp		*s;
	int				d, i, j;

#	ifdef xOTR1
	if (tTf(85, -1))
		printf("Exactkey\n");
#	endif

	a = ap;
	k = key;
	i = 0;
	if (a->mode == EXACTKEY)
	{

		for (i = 0; d = a->keydno[i]; i++)
		{
	
			s = De.ov_simp;
			for (j = 0; j < De.ov_nsimp; j++)
			{
				if (s->relop == opEQ && s->att == d)
				{
					k->keysym = s->constv;
					k->dnumber = (a->sec_index == TRUE) ? i+1 : d;
					k++;
#					ifdef xOTR1
					if (tTf(85, 1))
					{
						printf("exact key on dom %d\tvalue=", d);
						prsym(s->constv);
					}
#					endif
					break;
				}
				s++;
			}
			if (j == De.ov_nsimp)
			{
				i = 0;	/* failure. at lease one key isn't used */
				break;
			}
		}
		k->dnumber = 0;	/* mark end of list */
	}
#	ifdef xOTR1
	if (tTf(85, 9))
		printf("exactkey returning %d\n", i);
#	endif
	return (i);
}

/*
**	Attempts to use the B-Tree for retrieval.
**	There are two types of searches possible, exact and range searches.
**	In order for an exact search to be possible, there must be a simple
**	equality clause using the lid field.
**	For a range search, either or both lid ranges must be provided.
**
**	Returns		1  exact BTREEKEY search possible
**		       -1  low lid key provided
**		       -2  high lid key provided
**		       -3  both lids provided
*/

btreekey(lkey, hkey)

struct key *lkey, *hkey;
{
	register struct key	*l, *h;
	register struct simp	*s;
	int			i, j, k;
	int			provided[MAXLID];
	SYMBOL			*(save[MAXLID]);

#	ifdef xOTR1
	if (tTf(85, -1))
		printf("Btreekey\n");
#	endif

	l = lkey;
	h = hkey;
	i = 0;
	for (j = 0; j < MAXLID; ++j)
		provided[j] = 0;
	if (De.ov_scanr->reldum.reldim > 0 && De.ov_scanr->reldum.reltups > 0)
	{
		s = De.ov_simp;
		for (j = 0; j < De.ov_nsimp; ++j)
		{
			if (s->att >= De.ov_scanr->reldum.relatts - De.ov_scanr->reldum.reldim + 1)
			{
				if (s->relop == opEQ || s->relop == opGTGE)
				{
					l->keysym = s->constv;
					l->dnumber = s->att;
					if (s->relop == opEQ)
					{
						provided[De.ov_scanr->reldum.relatts - s->att] = 1;
						save[De.ov_scanr->reldum.relatts - s->att] = l->keysym;

					}
					else if (i == -2)
						i = -3;
					else if (!i)
						i = -1;
					++l;
				}
				if (s->relop == opLTLE)
				{
					h->keysym = s->constv;
					h->dnumber = s->att;
					h++;
					if (i == -1)
						i = -3;
					else if (!i)
						i = -2;
				}
			}
			s++;
			for (k = 0; k < De.ov_scanr->reldum.reldim; ++k)
				if (!provided[k])
					break;
			if (k >= De.ov_scanr->reldum.reldim)
			{
				i = 1;
				break;
			}
		}
		if (i != 1)
			for (k = 0; k < De.ov_scanr->reldum.reldim; ++k)
				if (provided[k])
				{
					h->keysym = save[k];
					h->dnumber = De.ov_scanr->reldum.relatts - k;
					h++;
					i = -3;
				}
		/* mark ends of lists */
		l->dnumber = 0;
		h->dnumber = 0;
	}
#	ifdef xOTR1
	if (tTf(85, 9))
		printf("btreekey returning %d\n", i);
#	endif
	return(i);
}
/*
**	Range key checks if the relation described by
**	"ap" is ISAM and there are simple clauses
**	on the first key and any additional keys.
**
**	Rangekey accumulates both high and low keys,
**	which are not necessary the same. If it
**	every finds a high or a low key on the first
**	domain of the relation then success=TRUE.
**
**	Returns  1 if Rangekey ok
**		 0 if Rangekey is not ok
**		-1 if Rangekey ok and all clauses are equality clauses
*/

rangekey(ap, l, h)
struct accessparam	*ap;
struct key		*l;
struct key		*h;
{
	register struct key	*low, *high;
	register struct simp	*s;
	struct accessparam	*a;
	int			sec_indx, d, i;
	int			rel, success, ns, lowkey, allexact;

#	ifdef xOTR1
	if (tTf(85, 5))
		printf("Rangekey\n");
#	endif

	a = ap;
	sec_indx  = a->sec_index == TRUE;
	low = l;
	high = h;
	allexact = -1;	/* assume all clauses equality clauses */
	s = De.ov_simp;
	success = FALSE;
	if (a->mode == LRANGEKEY)
	{

		for (ns = 0; ns < De.ov_nsimp; ns++)
		{
			rel = s->relop;
			for (i = 0; d = a->keydno[i]; i++)
			{
				if (d == s->att)
				{
					/* this is either a high range value or low range value */
					lowkey = (rel == opGTGE);
					if (lowkey || rel == opEQ)
					{
						/* low range key */
#						ifdef xOTR1
						if (tTf(85, 6))
							printf("low key on dom %d\t", d);
#						endif
						low->keysym = s->constv;
						low->dnumber = sec_indx ? i+1 : d;
						low++;
					}
					if (!lowkey || rel == opEQ)
					{
						/* high range key */
#						ifdef xOTR1
						if  (tTf(85, 6))
							printf("high key on dom %d\t", d);
#						endif
						high->keysym = s->constv;
						high->dnumber = sec_indx ? i+1 : d;
						high++;
					}
#					ifdef xOTR1
					if (tTf(85, 6))
						prsym(s->constv);
#					endif
					if (i == 0)
						success = TRUE;
					if (rel != opEQ)
						allexact = 1;	/* at least one inequality */
					break;
				}
			}
			s++;	/* try next simple clause */
		}
	}

	high->dnumber = 0;	/* mark end of list */
	low->dnumber = 0;	/* mask end of list */

	/* if success then return whether all clauses were equality */
	if (success)
		success = allexact;

#	ifdef xOTR1
	if (tTf(85, 5))
		printf("rangekey returning %d\n", success);
#	endif
	return (success);
}
/*
**	Setallkey takes a key struct, decodes it and
**	calls setkey with each value.
**
**	Called from strategy().
**
**	returns 0 if ok.
**	returns -1 in the special case of a deblanked hashkey
**	being bigger than the corresponding domain.
*/

setallkey(relkey, keytuple)
struct key	*relkey;
char		*keytuple;
{
	register struct key	*k;
	register SYMBOL		*sk;
	register int		dnum;
	struct symbol		**s;
	char			*p, temp[256];
	int			l;

	clearkeys(De.ov_scanr);
	k = relkey;
	while (dnum = k->dnumber)
	{
		s = &k->keysym;
		sk = (SYMBOL *) De.ov_stack;
		getsymbol(sk, &s);	/* copy symbol to stack. caution:getsym changes the value of s. */
		rcvt(sk, De.ov_scanr->relfrmt[dnum], De.ov_scanr->relfrml[dnum]);	/* convert key to correct type */
		p = (char *)&sk->value;

		if (sk->type == CHAR)
		{
			/*
			** The length of a character key must
			** be made equal to the domain length.
			** The key is copied to a temp place
			** and a null byte is inserted at the
			** end. In addition, if the key without
			** blanks is longer than the domain and
			** this is an exactkey, then the query
			** is false.
			*/
			p = temp;
			l = cmove(sk, p);	/* copy symbol to temp removing blanks & nulls */
#			ifdef xOTR1
			if (tTf(86, 9))
				printf("length is %d\n", l);
#			endif
			if (De.ov_fmode == EXACTKEY && l > (De.ov_scanr->relfrml[dnum] & I1MASK))
				/* key too large. qualification is false */
				return (-1);
		}
		setkey(De.ov_scanr, keytuple, p, dnum);	/* set the key */
		k++;
	}
#	ifdef xOTR1
	if (tTf(86, 8))
		printup(De.ov_scanr, keytuple);
#	endif
	return (0);
}
/*
**	Cmove copies a char symbol into "dest".
**	It stops when the length is reached or
**	when a null byte is found.
**
**	returns the number of non-blank chars
**	in the string.
*/

cmove(sym, dest)
SYMBOL	*sym;
char	*dest;
{
	register char	*d, *s;
	register int	l;
	int		blank;

	s = sym->value.sym_data.cptype;	/* s points to the char string */
	d = dest;
	blank = 0;

	for (l = (sym->len & I1MASK); l--; s++)
	{
		*d++ = *s;
		if (*s == ' ')
			blank++;
		if (*s == '\0')
		{
			d--;
			break;
		}
	}

	*d = '\0';
	return ((d - dest) - blank);	/* return length of string */
}
/*
**	Indexcheck is called by scan() to check whether
**	a secondary index tuple satisfies the simple
**	clauses under which it was scanned.
**
**	Returns 1 if the tuple is ok,
**		0 otherwise.
*/

indexcheck()
{
	register int	i;

	if (De.ov_fmode == EXACTKEY)
		i = keycheck(De.ov_lkey_struct, De.ov_keyl, 0);	/* check for equality */
	else
	{
		i = keycheck(De.ov_lkey_struct, De.ov_keyl, 1);	/* check for >= */
		/* If the lowkey passed, check the highkey also */
		if (i)
			i = keycheck(De.ov_hkey_struct, De.ov_keyh, -1);	/* check for <= */
	}
#	ifdef xOTR1
	if (tTf(86, 10))
		printf("indexcheck ret %d\n", i);
#	endif
	return (i);
}
/*
**	Keycheck compares De.ov_intup with keytuple
**	according to the domains specified in the
**	"keys" struct.
**
**	mode is either >0, =0, <0 depending on
**	whether check is for De.ov_intup >= keytuple,
**	De.ov_intup == keytuple, De.ov_intup <= keytuple respectively
**
**	returns TRUE or FALSE accordingly.
*/

keycheck(keys, keytuple, mode)
struct key	*keys;
char		*keytuple;
int		mode;
{
	register struct key	*k;
	register char		*kp;
	register int		dnum;
	int			offset, i, success;

	kp = keytuple;
	success = TRUE;

	for (k = keys; dnum = k->dnumber; k++)
	{

		offset = De.ov_scanr->reloff[dnum];
		if (i = icompare(&De.ov_intup[offset], &kp[offset], De.ov_scanr->relfrmt[dnum], De.ov_scanr->relfrml[dnum] & I1MASK))
		{
			if (i < 0 && mode < 0 || i > 0 && mode > 0)
				continue;
			success = FALSE;
			break;
		}
	}
	return (success);
}
