# include	<ingres.h>
# include	<aux.h>
# include	<symbol.h>
# include	<access.h>
# include	<lock.h>
# include	<btree.h>
# include	<sccs.h>

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


/*
**	Find - determine limits for scan of a relation
**
**	Find determines the values of an initial TID
**	and an ending TID for scanning a relation.
**	The possible calls to find are:
**
**	find(desc, NOKEY, lotid, hightid)
**		sets tids to scan entire relation
**
**	find(desc, EXACTKEY, lotid, hightid, key)
**		sets tids according to structure
**		of the relation. Key should have
**		been build using setkey.
**
**	find(desc, LRANGEKEY, lotid, hightid, keylow)
**		Finds lotid less then or equal to keylow
**		for isam relations. Otherwise scans whole relation.
**		This call should be followed by a call with HRANGEKEY.
**
**	find(desc, HRANGEKEY, lotid, hightid, keyhigh)
**		Finds hightid greater than or equal to
**		keyhigh for isam relations. Otherwise sets
**		hightid to maximum scan.
**
**	find(desc, FULLKEY, lotid, hightid, key)
**		Same as find with EXACTKEY and all keys
**		provided. This mode is used only by findbest
**		and replace.
**
**	returns:
**		<0 fatal error
**		 0 success
**
**	Trace Flags:
**		22.0-8
*/


find(d, mode, lotid, hightid, key)
register DESC	*d;
int		mode;
TID		*lotid;
TID		*hightid;
char		*key;
{
	register int	ret;
	bool		keyok;
	long		pageid, lid[MAXLID], page;
	long		rhash(), get_tid();
	struct locator  tid_id;
	char		*tp;
	int		i;
	extern int	Btree_fd;

#	ifdef xATR1
	if (tTf(22, 0))
	{
		printf("find: m%d,s%d,%.14s\n", mode, d->reldum.relspec, d->reldum.relid);
		if (mode != NOKEY)
			printup(d, key);
	}
#	endif

	ret = 0;	/* assume successful return */
	keyok = FALSE;

	switch (mode)
	{

	  case EXACTKEY:
		keyok = fullkey(d);
		break;

	  case FULLKEY:
		keyok = TRUE;

	  case NOKEY:
	  case LRANGEKEY:
	  case HRANGEKEY:
	  case BTREEKEY:
		break;

	  default:
		syserr("FIND: bad mode %d", mode);
	}

	/* set lotid for beginning of scan */
	if (mode != HRANGEKEY)
	{
		pageid = 0;
		stuff_page(lotid, &pageid);
		lotid->line_id = -1;
	}

	/* set hitid for end of scan */
	if (mode != LRANGEKEY)
	{
		pageid = -1;
		stuff_page(hightid, &pageid);
		hightid->line_id = -1;
	}

	if (mode == BTREEKEY)
	/* set tid to value as found using B-Tree */
	{
		tp = key + d->reldum.relwid - LIDSIZE * d->reldum.reldim;
		bmove(tp, lid, LIDSIZE * d->reldum.reldim);
		Btree_fd = d->btree_fd;
		page = RT;
		for (i = 0; i < d->reldum.reldim; ++i)
		{
			pageid = get_tid(page, lid[i], &tid_id);
			if (pageid < 0)
				break;
			page = pageid;
		}
		if (pageid >= 0)
			bmove(&pageid, lotid, LIDSIZE);

	}
	else if (mode != NOKEY)
	{
		switch (abs(d->reldum.relspec))
		{
	
		  case M_HEAP:
			break;
	
		  case M_ISAM:
			if (mode != HRANGEKEY)
			{
				/* compute lo limit */
				if (ret = ndxsearch(d, lotid, key, -1, keyok))
					break;	/* fatal error */
			}
	
			/* if the full key was provided and mode is exact, then done */
			if (keyok)
			{
				bmove((char *) lotid, (char *) hightid, sizeof *lotid);
				break;
			}
	
			if (mode != LRANGEKEY)
				ret = ndxsearch(d, hightid, key, 1, keyok);
			break;
	
		  case M_HASH:
			if (!keyok)
				break;		/* can't do anything */
			pageid = rhash(d, key);
			stuff_page(lotid, &pageid);
			stuff_page(hightid, &pageid);
			break;

		  default:
			ret = acc_err(AMFIND_ERR);
		}
	}

#	ifdef xATR2
	if (tTf(22, 1))
	{
		printf("find: ret %d\tlow", ret);
		dumptid(lotid);
		printf("hi");
		dumptid(hightid);
	}
#	endif
	return (ret);
}
/*
** This routine will check that enough of the tuple has been specified
** to enable a key access.
*/

fullkey(des)
DESC	*des;
{
	register DESC	*d;
	register int	i;

	d = des;
	for (i = 1; i <= d->reldum.relatts; i++)
		if (d->relxtra[i] && !d->relgiven[i])
			return (FALSE);
	return (TRUE);
}
