# include	"../ingres.h"
# include	"../access.h"

/*
** Seq_attributes - get all attributes of a relation in their correct order.
**
**	Seq_attributes() can be called when it is desired to get all
**	attribute tuples for a relation. They are guaranteed to be in
**	the same order as they were created in; that is "attid" order.
**
**	The calling convention is:
**
**		seq_init(Attribute_descriptor, Descriptor_for_relation)
**
**		while (seq_attributes(Att_desc, Des_for_rel, Tuple)
**		{
**		}
**
**	The first parameter is an OPEN descriptor for the attribute
**	relation. The second parameter is a descriptor for the relation.
**	It must have the relation-relation tuple (ie openr mode -1).
**	The third parameter is a place to put the attribute. Its
**	dimension must be at least sizeof (attribute structure).
**
**	Seq_attribute attempts to optimize the retrieval of the
**	attributes. It assumes initially that the are physically
**	stored sequentially. If so it will retrieve them in the
**	minimum possible number of accesses.
**
**	If it finds one tuple out of sequence then all future
**	scans will start from that first out of sequence tuple.
*/

struct tup_id	Seq_tdl, Seq_tdh, Seq_tdf;
int		Seq_seqmode, Seq_next;



seq_init(atr, rel)
struct descriptor	*atr;
struct descriptor	*rel;
{
	register struct descriptor	*a, *r;
	register int			i;
	struct attribute		attkey;

	a = atr;
	r = rel;

	clearkeys(a);
	setkey(a, &attkey, r->relid, ATTRELID);
	setkey(a, &attkey, r->relowner, ATTOWNER);
	if (i = find(a, EXACTKEY, &Seq_tdl, &Seq_tdh, &attkey))
		syserr("seq_init:find:%d", i);

	Seq_seqmode = TRUE;
	Seq_next = 1;
}


seq_attributes(atr, rel, att_tuple)
struct descriptor	*atr;
struct descriptor	*rel;
struct attribute	*att_tuple;
{
	register struct descriptor	*a, *r;
	register struct attribute	*atup;
	int				i, nxttup;

	a = atr;
	r = rel;
	atup = att_tuple;

	if (Seq_next > r->relatts)
		return (0);	/* no more attributes */

	if (!Seq_seqmode)
	{
		/* attributes not stored sequencially, start from first attribute */
		bmove(&Seq_tdf, &Seq_tdl, sizeof (Seq_tdl));
		nxttup = FALSE;
	}
	else
		nxttup = TRUE;

	while ((i = get(a, &Seq_tdl, &Seq_tdh, atup, nxttup)) == 0)
	{

		nxttup = TRUE;
		/* make sure this is a tuple for the right relation */
		if (kcompare(a, atup, r))
			continue;

		/* is this the attribute we want? */
		if (atup->attid != Seq_next)
		{
			if (Seq_seqmode)
			{
				/*
				** Turn off seq mode. Save the tid of
				** the current tuple. It will be the
				** starting point for the next call
				** to seq_attributes
				*/
				bmove(&Seq_tdl, &Seq_tdf, sizeof (Seq_tdf));
				Seq_seqmode = FALSE;
			}

			continue;
		}

		/* got current attribute. increment to next attribute */
		Seq_next++;
		return (1);
	}

	/* fell out of loop. either bad get return or missing attribute */
	syserr("seq_att:bad or missing %d,%d", i, Seq_next);
}
