# include	<ingres.h>
# include	<aux.h>
# include	<tree.h>
# include	<symbol.h>
# include	<range.h>
# include	"parser.h"
# include	<sccs.h>
# include	<errors.h>

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

/*
**	Range table variables
*/

PARRNG			Parrng[MAXRANGE]; /* table for keeping track of atts */
					  /* and allocation of range vars */
int			Resrng;		/* result reln slot */

PARRNG			*Rngfront;	/* the front of Rnga */
PARRNG			*Rngback;	/* the back of Qt.qt_rangev */


/*
**  RANGE_FCN.C -- functions for manipulating the range table
**
**	Trace Flags:
**		RANGE_FCN.C ~~ 66, 67
*/

ctlmod_decl(slot)
int	slot;
{
	extern PARRNG	Parrng[];

	Qt.qt_rangev[slot].rngvdesc = NULL;
	if (declare(slot, &Parrng[slot].vardesc) != slot)
		syserr("declare misdeclared");
}

/*
**  RNGINIT
**	initializes the pointers in the range table
**	it should be called prior to starting the parsing
**	it also initializes the attrib stash stuff because
**	the attrib stash is really part of the range table
**
**	Trace Flags:
**		rnginit ~~ 66.0
*/
rnginit()
{
	register int		slot;
	register PARRNG		*parrngptr;
	register RANGEV		*rngptr;

#	ifdef	xPTR2
	tTfp(66, 0, "rnginit\n");
#	endif

	Rngfront = &Parrng[MAXVAR - 1];			/* ptr to head of range table */
	parrngptr = Parrng;
	/* initialize first element */
	parrngptr->attlist = NULL;
	parrngptr->backpt = NULL;
	parrngptr->frontpt = &Parrng[1];

	rngptr = Qt.qt_rangev;

	for (slot = 0, parrngptr = &Parrng[1]; slot < MAXVAR; slot++, parrngptr++)
	{
		parrngptr->attlist = NULL;

		parrngptr->frontpt = parrngptr + 1;
		parrngptr->backpt = parrngptr - 1;
	}

	Rngback = Parrng;

	parrngptr = &Parrng[MAXVAR - 1];

	parrngptr->frontpt = NULL;

	/* MAXVAR SLOT = Resultvar */
	(++parrngptr)->attlist = NULL;
	parrngptr->frontpt = parrngptr->backpt = NULL;

	Rngfront->frontpt = NULL;

	clrrange();

	attinit();
}

/*
** RNGLOOK
**	returns a pointer to the range table entry else -1
**	type = LOOKREL	lookup relation
**	type = LOOKVAR	lookup variable
**
**	Trace Flags:
**		rnglook ~~ 66.4, 66.5, 66.6
*/
int
rnglook(name, type)
char		*name;
int		type;
{
	register PARRNG		*rptr;

	register int		slot;

	DESC			reldesc;

	int			i;

#	ifdef	xPTR2
	tTfp(66, 4, "rnglook:\ttype = %s\tname = %s\n",
		    (type == LOOKVAR ? "variable" : "relation"), name);

	if (tTf(66, 5))
		printtable();
#	endif

	rptr = Parrng;

	for (slot = 0; slot < MAXVAR; slot++, rptr++)	/* search external vbles only */
	{
		if (rptr->relvused
		    && scompare(name, MAXNAME,
		    (type == LOOKVAR ? rptr->vardesc.relvname : rptr->vardesc.reldum.relid),
		    MAXNAME) == 0)
		{
			Qt.qt_rangev[slot].rngvmark = 1;
			
#			ifdef	xPTR2
			tTfp(66, 6, "fnd '%s' at '%d'\n", name, slot);
#			endif

			rngfront(slot);
			return (slot);
		}
	}

	/*
	** We haven't been able to find the variable, assume 
	** it is the name of a relation, and try and insert
	** a new range variable under that name.
	*/
	if (type == LOOKVAR)
	{
		if ((i = openr(&reldesc, OR_RELTID, name)) < 0)
			syserr("relname: error in openr '%d'", i);

		/*
		** rngent will call rnglook to create var if name
		** was a relation name
		*/
		if (i == 0)
			return(rngent(R_IMPLICIT, name, &reldesc));
		else
			return(-1);
	}
	return (-1);
}

/*
**  RNGENT
**
**	Insert variable and relation in range table.
**
**	Trace Flags:
**		 rngent ~~ 66.8
*/

int
rngent(type, var, desc)
int			type;
char			*var;
register DESC		*desc;
{
	register PARRNG	*rptr;
	register int	slot;

#	ifdef	xPTR2
	tTfp(66, 8, "rngent:\ttype=%s\tvar=%s\n",
		(type == R_INTERNAL ? "internal" : "external"), var);
#	endif

	if (type == R_INTERNAL)
		slot = MAXVAR;		/* the internal variable */
	else
	{
		if ((type == R_IMPLICIT) || (slot = rnglook(var, LOOKVAR)) < 0)
		{
			/* not in range table */
			slot = rngold();
		}

		rngfront(slot);
	}

	rptr = &Parrng[slot];

	if (!bequal(desc, &rptr->vardesc, sizeof (*desc)))
	{
		attfree(rptr->attlist);
		rptr->attlist = NULL;
	}

	rptr->relvused = 1;

	bmove(desc, &rptr->vardesc, sizeof(*desc));
	pmove(var, rptr->vardesc.relvname, MAXNAME, ' ');

	ctlmod_decl(slot);

	return (slot);
}

/*
** RNGDEL
**	removes an entry from the range table
**	removes all variables for the relation name
**
**	Trace Flags:
**		 rngdel ~~ 66.12
*/
rngdel(rel)
register char	*rel;
{
	register int	slot;

# ifdef	xPTR2
	tTfp(66, 12, "rngdel: %12s\n", rel);
# endif

	while ((slot = rnglook(rel, LOOKREL)) >= 0)
	{
		Parrng[slot].relvused = 0;
		rngback(slot);
		attfree(Parrng[slot].attlist);
		Parrng[slot].attlist = NULL;
	}
}


/*
** RNGFRONT
**	move entry 'r' to head of range table list
**
**	Trace Flags:
**		 rngfront ~~ 67.0 
*/
rngfront(slot)
int	slot;
{
	register PARRNG		*fptr;

#	ifdef	xPTR2
	tTfp(67, 0, "rngfront:\tslot %d\n", slot);
#	endif


	rngget(slot);

	fptr = &Parrng[slot];

	fptr->frontpt = NULL;
	fptr->backpt = Rngfront;
	Rngfront->frontpt = fptr;

	Rngfront = fptr;
}

/*
** RNGBACK
**	move entry 'r' to back of range table list
**
**	Trace Flags:
**		rngback ~~ 67.4
*/
rngback(slot)
int	slot;
{
	register PARRNG	*bptr;

#	ifdef	xPTR2
	tTfp(67, 4, "rngback:\tslot %d\n", slot);
#	endif

	rngget(slot);

	bptr = &Parrng[slot];

	bptr->backpt = NULL;
	bptr->frontpt = Rngback;
	Rngback->backpt = bptr;

	Rngback = bptr;
}

/*
**  RNGGET -- get a descriptor from range table
**
**	Trace Flags:
**		rngget ~~ 67.8
*/

rngget(slot)
int	slot;
{
	register PARRNG	*slotptr;
	register PARRNG	*forward;
	register PARRNG	*backward;

#	ifdef	xPTR2
	tTfp(67, 8, "rngget:\tslot %d\n", slot);
#	endif


	slotptr = &Parrng[slot];
	forward = slotptr->frontpt;
	backward = slotptr->backpt;

	if (slotptr == Rngfront)
	{
		Rngfront = backward;
		backward->frontpt = NULL;
	}
	else if (slotptr == Rngback)
	{
		Rngback = forward;
		forward->backpt = NULL;
	}
	else
	{
		forward->backpt = backward;
		backward->frontpt = forward;
	}

	slotptr->backpt = slotptr->frontpt = NULL;
}

/*
**  RNGOLD -- find least recently used vble entry
**
**	Trace Flags:
**		rngold ~~ 67.9
*/
int
rngold()
{
# ifdef	xPTR2
	tTfp(67, 9, "rngold %d.\n", Rngback - (PARRNG *) Parrng);
# endif

	return(Rngback - (PARRNG *) Parrng);
}

/*
** RNGRESET
**	reset the used marks to '0'
**
**	Trace Flags:
**		rngreset ~~ 67.10
*/
rngreset()
{
	register int		i;
	register RANGEV		*rangevptr;

# ifdef	xPTR2
	tTfp(67, 10, "rngreset().\n");
# endif

	rangevptr = Qt.qt_rangev;

	for (i = 0; i < MAXVAR; i++, rangevptr++) /* only do external ones */
		rangevptr->rngvmark = 0;
}

/*
** CHECKUPD
**	checks to make sure that the user can update the relation 'name1'
**	the 'open' parameter is set if 'Reldesc' contains the openr info
**	for the relation in question.
**
**	Trace Flags:
**		checkupd ~~ 67.11
*/
checkupd(entnum)
int	entnum;
{
	extern int		Noupdt;
	extern PARRNG		Parrng[];
	register PARRNG		*rptr;

# ifdef	xPTR2
	tTfp(67, 11, "checkupd(%d).\n", entnum);
# endif

	rptr = &Parrng[entnum];

	if (!Noupdt)
		return;
	if (rptr->vardesc.reldum.relstat & S_NOUPDT)
		/* no updates allowed on this relation */
		par_error(CANTUPDATE, WARN, trim_relname(rptr->vardesc.reldum.relid), 0);
}

/*
** RNGFRESH -- check the range table relstat information for accuracy
**
**	If the command specified could have changed the relstat info
**	make the appropriate adjustments to the range table
*/
rngfresh(op)
int	op;
{
	register PARRNG		*rptr;
	register int		slot;
	DESC			desc;
	char			var[MAXNAME];

# ifdef	xPTR2
	tTfp(67, 11, "rngfresh %d.\n", op);
# endif

	/* search the entire table! */
	for (slot = 0, rptr = Parrng; slot <= MAXVAR; slot++, rptr++)
	{
		if (!(rptr->relvused))
			continue;

		switch (op)
		{
		  case mdDESTROY:
			if ((rptr->vardesc.reldum.relstat & (S_VBASE | S_INTEG | S_PROTUPS | S_INDEX)) != 0)
			{
			fixordel:
				/*
				** openr the relation, if it doesn't exist make
				** sure that all range table entries are gone
				*/
				if (!openr(&desc, OR_RELTID, rptr->vardesc.reldum.relid))
					rptr->vardesc.reldum.relstat = desc.reldum.relstat;
				else
					/* relation not there, purge table */
					rngdel(rptr->vardesc.reldum.relid);
			}
			break;

		  case mdVIEW:
			if ((rptr->vardesc.reldum.relstat & S_VBASE) == 0)
			{
			fixorerr:
				/*
				** if the relation doesn't exist then it is
				** a syserr, otherwise, copy the bits.
				*/
				if (!openr(&desc, OR_RELTID, rptr->vardesc.reldum.relid))
					rptr->vardesc.reldum.relstat = desc.reldum.relstat;
				else
				{
					/* not there, syserr */
					syserr("RNGFRESH: extra entry: %s", rptr->vardesc.reldum.relid);
				}
			}
			break;

		  case mdPROT:
			if ((rptr->vardesc.reldum.relstat & S_PROTUPS) == 0)
				goto	fixorerr;
			break;

		  case mdINTEG:
			if ((rptr->vardesc.reldum.relstat & S_INTEG) == 0)
				goto	fixorerr;
			break;

		  case mdMODIFY:
			if (!openr(&desc, OR_RELTID, rptr->vardesc.reldum.relid))
				if (!bequal(&rptr->vardesc, &desc, sizeof desc))
				/* relation structure may have changed, adjust range variable */
				{
					bmove(rptr->vardesc.relvname, var, MAXNAME);
					rngent(R_EXTERNAL, var, &desc);
				}
			if ((rptr->vardesc.reldum.relstat & S_INDEX) != 0)
				goto	fixordel;
			break;
		
		  default:
			return;	/* command ok, dont waste time on rest of table */
		}
	}
}

printtable()
{
	register PARRNG		*rptr;
	int			slot[MAXRANGE];
	int			i;

	printf("Range table:\n");

	for (i = 0; i < MAXRANGE; i++)
		slot[i] = 0;

	for (rptr = Rngfront; rptr != NULL; rptr = rptr->backpt)
	{
		i = rptr - (PARRNG *) Parrng;
		slot[i] = 1;
		printslot(i);
	}
	printf("\nEntries not in list:\n");
	for (i = 0; i < MAXRANGE; i++)
	{
		if (!slot[i])
		{
			printslot(i);
		}
	}
}

printslot(slot)
int	slot;
{
	register RANGEV		*rptr;
	register PARRNG		*auxptr;

	rptr = &Qt.qt_rangev[slot];
	auxptr = &Parrng[slot];

	printf("slot:\t%d\n{\trvar:\t%.12s,\trelnm:\t%.12s.\n",
	    slot, auxptr->vardesc.relvname,
	    auxptr->vardesc.reldum.relid);
	printf("\tRELVUSED: %d, RELVSEND %d.\n",
	    auxptr->relvused,
	    rptr->rngvmark);


	printf("\tratts: %d, attlist: %d.\n}\n", auxptr->vardesc.reldum.relatts, auxptr->attlist);
}
