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

SCCSID(@(#)batch.c	8.2	1/17/85)

/*
**	Open batch prepares for batch processing.
**	1. If the batch is already open, return an error
**	2. Create the batch file.
**	3. clear domain flags.
**	4. If the relation is indexed, Identify all the domains
**		which must be saved to speed the index update.
**	5. Set up specifics for each type of update.
**	6. Write out the batch structure.
**
**	The following itemizes what is saved (in bytes):
**	f(si) means it's a function of the secondary index keys
**	space for newtid is saved only if there is a sec. index.
**
**			mdDEL	mdREPL	mdAPP
**
**	oldtid		4	4	0
**	oldtuple	f(si)	f(si)	0
**	newtuple	0	tupwid	tupwid
**	newtid		0	4	4
*/

openbatch(rel_desc, index_desc, mode)
DESC	*rel_desc, *index_desc;
int	mode;
{
	register struct si_doms	*sp;
	register DESC		*rel, *indx;
	int			i, j, saveoff, dom;
	char			*p, *batchname();
	TID			lotid, hitid;
	struct index		itup;
	extern char		*Database;

	if (Batchhd.mode_up)
		return (-1);	/* batch already open */
	rel = rel_desc;
	indx = index_desc;
	p = batchname();	/* form batch name */
#	ifdef xATR1
	if (tTf(25, -1))
		printf("Openbatch %s\n", p);
#	endif
	if ((Batch_fp = creat(p, FILEMODE)) < 0)
		syserr("openbatch:can't creat %s,%d", p, Batch_fp);
	Batch_cnt = 0;

	/* copy the important info */
	smove(Fileset, Batchbuf.file_id);
	smove(Database, Batchhd.db_name);
	bmove(rel->reldum.relid, Batchhd.rel_name, MAXNAME);
	bmove(rel->reldum.relowner, Batchhd.userid, 2);
	Batchhd.mode_up = mode;
	Batchhd.num_updts = 0;

	/* clear out the secondary index domain flags */
	sp = Batchhd.si;	/* sp points to the structure */
	for (i = 1; i <= MAXDOM; i++)
	{
		sp->dom_size = 0;
		sp++;
	}
	Batchhd.si_dcount = 0;

	/* set up the tid and tuple sizes by type of update */
	/* assume size of tido, tidn, and tupn */
	Batchhd.tido_size = 4;	/* assume old tid is needed */
	Batchhd.tupo_size = 0;	/* assume old tuple isn't needed */
	Batchhd.tupn_size = rel->reldum.relwid;	/* assume new tuple is needed */
	Batchhd.tidn_size = 4;	/* assume space is needed for new tid */
	switch(Batchhd.mode_up)
	{

	  case mdDEL:
		Batchhd.tupn_size = 0;	/* new tuple isn't needed */
		Batchhd.tidn_size = 0;	/* new tid isn't needed */

	  case mdREPL:
		break;

	  case mdAPP:
		Batchhd.tido_size = 0;	/* old tid isn't needed */
		break;

	  default:
		syserr("openbatch:mode %d", Batchhd.mode_up);
	}
	/* if there are no secondary indexes then tipn isn't needed, unless 
	** relation is ordered
	*/
	if (rel->reldum.relindxd <= 0 && rel->reldum.reldim <= 0)
		Batchhd.tidn_size = 0;

	/* if this relation has a secondary index or an ordered relation,
	** figure out what to save 
	*/
	if ((rel->reldum.relindxd > 0 || rel->reldum.reldim > 0) && mode != mdAPP)
	{
		if (rel->reldum.relindxd > 0)
		{
			setkey(indx, (char *) &itup, rel->reldum.relid, IRELIDP);
			setkey(indx, (char *) &itup, rel->reldum.relowner, IOWNERP);
	
			if (find(indx, EXACTKEY, &lotid, &hitid, (char *) &itup))
				syserr("openbatch:bad find %.12s", rel);
	
			/* check each entry in "index" relation for useful index */
			while(!(i = get(indx, &lotid, &hitid, (char *) &itup, TRUE)))
			{
				if (!bequal(itup.irelidp, rel->reldum.relid, MAXNAME) ||
				    !bequal(itup.iownerp, rel->reldum.relowner, 2))
					continue;
				/* found one. copy the used domains */
				p = itup.idom;		/* get address of first */
				i = 6;
				while (i--)
				{
					if ((dom = *p++) == 0)
						break;	/* no more domains */
					sp = &Batchhd.si[dom];
					if (sp->dom_size != 0)
						continue;	/* domain has already been done once */
					Batchhd.si_dcount++;
					Batchhd.tupo_size += rel->relfrml[dom] & I1MASK;
					sp->rel_off = rel->reloff[dom];
					sp->dom_size = rel->relfrml[dom] & I1MASK;
				}
			}
		}
		for (j = rel->reldum.reldim - 1; j >= 0; --j)
		{
			/* point to lid field */
			sp = &Batchhd.si[rel->reldum.relatts - j];
			Batchhd.si_dcount++;
			Batchhd.tupo_size += LIDSIZE;
			sp->rel_off = rel->reloff[rel->reldum.relatts - j];
			sp->dom_size = LIDSIZE;
		}
		if (i < 0)
			syserr("openbatch:bad get index %d", i);
		/* compute offsets of domains in saved "oldtuple" */
		saveoff = 0;
		sp = Batchhd.si;
		i = Batchhd.si_dcount;
		while (i--)
		{
			/* skip to next domain */
			while (sp->dom_size == 0)
				sp++;
			sp->tupo_off = saveoff;
			saveoff += sp->dom_size;
			sp++;
		}
	}
	wrbatch((char *) &Batchhd, sizeof Batchhd);
	return (0);
}
/*
**  ADDBATCH -- add to batch file
*/

addbatch(oldtid, newtuple, oldtuple)
TID	*oldtid;
char	*newtuple, *oldtuple;
{
	TID			newtid;
	register int		i;
	register struct si_doms	*sp;
	register char		*old;

#	ifdef xATR1
	if (tTf(25,3))
		printf("addbatch\n");
#	endif
	if (Batchhd.mode_up == 0)
		return (-1);
	Batchhd.num_updts++;	/* increment the number of add batches */
	old = oldtuple;
	/* write out the old tid */
	wrbatch((char *) oldtid, Batchhd.tido_size);

	/* write out each of the old tuple domains */
	i = Batchhd.si_dcount;	/* i get the number of domains */
	sp = Batchhd.si;	/* sp points to the domain structures */

	while (i--)
	{
		/* skip to the next domain */
		while (sp->dom_size == 0)
			sp++;

		wrbatch(&old[sp->rel_off], sp->dom_size);
		sp++;
	}

	/* write out the new tuple */
	wrbatch(newtuple, Batchhd.tupn_size);

	/* reserve space for the new tid. Init to -1 */
	*((long *) &newtid) = -1;
	wrbatch((char *) &newtid, Batchhd.tidn_size);
	return (0);
}
/*
**  CLOSEBATCH -- close batch file
*/

closebatch()
{
	register int	i;
	extern long	lseek();

	if (Batchhd.mode_up == 0)
		return (-1);
	flushbatch();	/* write out any remainder */
	if ((i = lseek(Batch_fp, 0l, 0)) == -1)
		syserr("closebatch:seek %d", i);
	wrbatch((char *) &Batchhd, sizeof Batchhd);	/* update num_updts */
	flushbatch();
	if (i = close(Batch_fp))
		syserr("closebatch:close %d", i);
	Batchhd.mode_up = 0;
	return (0);
}
