static	char	testbuf_c[] = "$Header: /private/postgres/src/test/RCS/testbuf.c,v 1.9 1992/03/04 14:10:52 hong Exp $";

#include <stdio.h>

#include "postgres.h"
#include "skey.h"
#include "fmgr.h"
#include "htup.h"
#include "log.h"
#include "rlock.h"

#include "buf.h"
#include "bufmgr.h"
#include "itemptr.h"
#include "tqual.h"

#include "storage/smgr.h"

/*
 *	testbuf.c	- code to test the buffer code
 *
 *	Tuples are inserted in one of two formats:
 *		< odd_pos_int, NULL, NULL, NULL >
 *		< even_pos_int, NULL, "12345671234567123...", 0xfe9a >
 */

#define	NATTS	(4)
#define	ENDVAL	0xfe9a

static	char	Relname[] = "testbufrel";

static	struct	attribute a1 =
	{0l, "testbufatt", 23, 0l, 0l, 0l, 4, 1, 0, '\001', '\001'};
static	struct	attribute a2 =
	{0l, "testbufnull", 25, 0l, 0l, 0l, -1, 2, 0, '\000', '\001'};
static	struct	attribute a3 =
	{0l, "testbufvar", 25, 0l, 0l, 0l, -1, 3, 0, '\000', '\001'};
static	struct	attribute a4 =
	{0l, "testbufpost", 21, 0l, 0l, 0l, 2, 4, 0, '\001', '\001'};
static	struct	attribute *Att[NATTS] = { &a1, &a2, &a3, &a4 };

static	char			Null[] = " n  ";
static	struct	reldesc		*Reldesc;
static	struct	outdom {
	long	i;
	char	*null;
	char	*string;
	long	end;
} dom = { 0l, "367", 0, ENDVAL };

static	struct	indom {
	long		i;
	long		systemtextlen;
	struct	varlena	vlena;
};

TestMain()
{
	static	int	existant = 0;
	int		i, j;
	ItemPointerData	tid;
	char		*dat;

	struct	reldesc	*amopenr();
	extern		heap_create();
	extern		iinsert(), iprinttup(), showrelall();

	StartTransactionCommand();
	startmmgr(0);
	if (!existant) {
		existant = 1;
		heap_create(Relname, 'n', NATTS, DEFAULT_SMGR, Att);
		CommitTransactionCommand();
		StartTransactionCommand();
	}
	Reldesc = amopenr(Relname);
	puts("Insert a list of numbers (<0)? (page,line for tid)");
	for (;;) {
		if (scanf("%ld", &i) != 1)
			break;
		startmmgr(1);
		if (i < 0)
			iinsert(-i);
		else {
			if (scanf(",%d", &j) != 1)
				break;
			ItemPointerSimpleSet(&tid, i, j);
			iprinttup(&tid);
		}
		endmmgr(NULL);
		CommitTransactionCommand();
		StartTransactionCommand();
	}
	puts("bye...");
	showrelall();
	endmmgr(NULL);
	CommitTransactionCommand();
}

iinsert(i)
int	i;
{
	int		j;
	char		*s;
	struct	tuple	*tup;
	struct	tuple	*addtupleheader();
	struct	tuple	*formtuple();
	RuleLock	aminsert();
	struct	varlena	*textin();
	extern		pfree();

	if (i & 01)
		tup = addtupleheader(1, 4, (char *)&i);
	else {
		dom.i = i;
		s = palloc(1 + i / 2);
		for (j = 0; j < i / 2; j++)
			s[j] = '1' + j % 7;
		s[j] = '\0';
		dom.string = (char *)textin(s);
		pfree(s);
		tup = formtuple(4, Att, (char *)&dom, Null);
	}
	aminsert(Reldesc, tup, (double *)NULL);
	printf("inserted id %ld (length %lu) at %ld,%d\n", i, tup->t_len,
		ItemPointerGetBlockNumber(&tup->t_ctid),
		ItemPointerSimpleGetOffsetNumber(&tup->t_ctid));
	pfree((char *)tup);
}

iprinttup(tid)
ItemPointer	tid;
{
	int		j;
	unsigned	iden;
	char		*s;
	struct	tuple	*tup;
	Buffer		b;
	Boolean		isnull;
	TUPLE		*amgetunique();
	char		*getstruct();
	char		*amgetattr();

	if ((tup = (struct tuple *)amgetunique(Reldesc, NowTimeQual, tid, &b))
			!= NULL) {
		(void)amgetattr(tup, b, 2, Att, &isnull);
		if (!isnull) {
			fputs("Non-null second attribute!", stderr);
			exitpg(1);
		}
		(void)amgetattr(tup, b, 3, Att, &isnull);
		if (isnull) {
			iden = ((struct indom *)getstruct(tup))->i;
			printf("Retrieved %ld from %ld,%d\n", iden,
				ItemPointerGetBlockNumber(tid),
				ItemPointerSimpleGetOffsetNumber(tid));
		} else {
			iden = (long)amgetattr(tup, b, 1, Att, &isnull);
			/* check isnull */
			printf("Retrieved %ld (length %lu) from %ld,%d\n",
				iden, tup->t_len,
				ItemPointerGetBlockNumber(tid),
				ItemPointerSimpleGetOffsetNumber(tid));
			if ((short)amgetattr(tup, b, 4, Att, &isnull) !=
					(short)ENDVAL)
				/* check isnull */
				fprintf(stderr, "Fourth attribute is %d!\n",
					amgetattr(tup, b, 4, Att, &isnull));
				/* check isnull */
			s = amgetattr(tup, b, 3, Att, &isnull);
			/* check isnull */
			if (sizeof (long) + iden / 2 !=
					((struct varlena *)s)->vl_len ||
					sizeof (long) + iden / 2 !=
					psize(s)) {
				printf("*** Lengths %ld, %ld, %ld\n",
					sizeof (long) + iden / 2, psize(s),
					((struct varlena *)s)->vl_len);
				return;
			}
			s += sizeof (long);
			for (j = 0; j < iden / 2; j++, s++)
				if (*s - j % 7 != '1')
					printf("data[%d] is %c not %c.\n",
					       j, *s, '1' + j % 7);
			ReleaseBuffer(b);
		}
	} else
		printf("No tuple at %d\n", tid);
}

showrelall()
{
	struct	relscan	*sdesc;
	struct	tuple	*tup;
	Buffer		b;
	Boolean		isnull;
	struct	relscan	*ambeginscan();
	struct	tuple	*amgetnext();
	extern		amendscan();
	char		*getstruct();
	extern		pfree();

	sdesc = ambeginscan(Reldesc, 0, NowTimeQual, 0, (struct skey *)NULL);
	startmmgr(0);
	while ((tup = amgetnext(sdesc, 0, &b)) != (struct tuple *)NULL) {
		(void)amgetattr(tup, b, 3, Att, &isnull);
		if (isnull) {
			printf("id %ld at %ld,%d\n",
				((struct indom *)getstruct(tup))->i,
				ItemPointerGetBlockNumber(&tup->t_ctid),
				ItemPointerSimpleGetOffsetNumber(&tup->t_ctid));
		} else {
			OID	id;

			id = (OID)amgetattr(tup, b, 1, Att, &isnull);
			if (isnull) {
				printf("id *NULL* ???\n");
			} else {
				printf("id %ld (length %lu) at %ld,%d\n",
					(long)id, tup->t_len,
					ItemPointerGetBlockNumber(&tup->t_ctid),
					ItemPointerSimpleGetOffsetNumber(&tup->t_ctid));
			}
		}
		endmmgr(NULL);
		startmmgr(0);
	}
	endmmgr(NULL);
	amendscan(sdesc);
}
