static	char	amiint_c[] = "$Header: RCS/oamiint.c,v 1.7 89/10/10 16:40:52 hirohama Exp $";

#include <sys/file.h>
#include <stdio.h>
#include <setjmp.h>
#include <strings.h>
#include <signal.h>
#include "fmgr.h"
#include "catalog.h"

#include "c.h"

#include "bufmgr.h"	/* for BufferManagerFlush */
#include "buf.h"
#include "defind.h"
#include "log.h"
#include "htup.h"
#include "rel.h"
#include "relscan.h"
#include "rlock.h"
#include "skey.h"
#include "tim.h"
#include "trange.h"
#include "xcxt.h"
#include "xid.h"

extern char *calloc();
#define ALLOC(t, c)	(t *)calloc((unsigned)(c), sizeof(t))

extern struct attribute	*aalloc();
extern int	die();

#define DISABLE_BOOTSTRAP()	;	/* XXX ???	*/
#define ENABLE_BOOTSTRAP()	;

#define FIRST_TYPE_OID 16	/* OID of the first type */
#define	MAXATTR 40		/* max. number of attributes in arelation */

typedef	enum {
	Q_OID, Q_LEN, Q_DYN, Q_IN, Q_OUT, Q_EQ, Q_LT
} QUERY;

/* types recognized */
typedef	enum	{
	TY_BOOL, TY_BYTEA, TY_CHAR, TY_CHAR16, TY_DATETIME, TY_INT2, TY_INT28,
	TY_INT4, TY_REGPROC, TY_TEXT, TY_OID, TY_TID, TY_XID, TY_CID,
	TY_OID8
} TYPE;
#define	TY_LAST	TY_OID8

static char *   (typestr[15]) = {
	"bool", "bytea", "char", "char16", "dt", "int2", "int28",
	"int4", "regproc", "text", "oid", "tid", "xid", "iid",
	"oid8"
};

/* functions associated with each type */
static	long	Procid[15][7] = {
	{ 16, 1, 0, F_BOOLIN, F_BOOLOUT, F_BOOLEQ, NULL },
	{ 17, -1, 1, F_BYTEAIN, F_BYTEAOUT, NULL, NULL },
	{ 18, 1, 0, F_CHARIN, F_CHAROUT, F_CHAREQ, NULL },
	{ 19, 16, 1, F_CHAR16IN, F_CHAR16OUT, F_CHAR16EQ, NULL },
	{ 20, 4, 0, F_DATETIMEIN, F_DATETIMEOUT, NULL, NULL },
	{ 21, 2, 0, F_INT2IN, F_INT2OUT, F_INT2EQ, F_INT2LT },
	{ 22, 16, 1, F_INT28IN, F_INT28OUT, NULL, NULL },
	{ 23, 4, 0, F_INT4IN, F_INT4OUT, F_INT4EQ, F_INT4LT },
	{ 24, 4, 0, F_REGPROCIN, F_REGPROCOUT, NULL, NULL },
	{ 25, -1, 1, F_TEXTIN, F_TEXTOUT, F_TEXTEQ, NULL },
	{ 26, 4, 0, F_INT4IN, F_INT4OUT, F_INT4EQ, NULL },
	{ 27, 6, 1, F_TIDIN, F_TIDOUT, NULL, NULL },
	{ 28, 5, 1, F_XIDIN, F_XIDOUT, NULL, NULL },
	{ 29, 1, 0, F_CIDIN, F_CIDOUT, NULL, NULL },
	{ 30, 32, 1, F_OID8IN, F_OID8OUT, NULL, NULL }
};

struct	typmap {			/* a hack */
	OID		am_oid;
	struct	type	am_typ;
};

static	struct	typmap	**Typ = (struct typmap **)NULL;
static	struct	typmap	*Ap = (struct typmap *)NULL;

/*
static struct context	*RelationOpenContext = NULL;
*/

static	int	Quiet = 0;
static	int	Warnings = 0;
static	int	ShowTime = 0;
#ifdef	EBUG
static	int	ShowLock = 0;
#endif
static	char	Blanks[MAXATTR];
static	char	Buf[MAXPGPATH];
int		Userid;
Relation	reldesc;		/* current relation descritor */
char		relname[80];		/* current relation name */
struct	attribute *attrtypes[MAXATTR];	/* points to attribute info */
char		*values[MAXATTR];	/* cooresponding attribute values */
int		numattr;		/* number of attributes for cur. rel */
static TimeRange	StandardTimeRange = DefaultTimeRange;
static TimeRangeSpace	StandardTimeRangeSpace;
jmp_buf		Warn_restart;

extern
   struct context	*topcontext();

bool override = false;



main(argc, argv)
int	argc;
char	*argv[];
{
	int		i;
	int		flagC, flagQ;
	int		flag, errs = 0;
	char		*dat;
	extern	int	Noversion;		/* util/version.c */
	extern	int	Quiet;
	extern	char	Blanks[], Buf[];
	extern	jmp_buf	Warn_restart;
	extern	int	optind;
	extern	char	*optarg;
	int		cinit(), handle_warn();
	int		setjmp(), chdir();
	char		*getenv();
	extern		resetmmgr();

	flagC = flagQ = 0;
	while ((flag = getopt(argc, argv, "CQO")) != EOF)
		switch (flag) {
		case 'C':
		   flagC = 1;
		   break;
		case 'Q':
		   flagQ = 1;
		   break;
		case 'O':
		   override = true;
		  break;
		default:
			errs += 1;
		}
	if (errs || argc - optind > 1) {
		goto usage;
	} else if (argc - optind == 1) {
		dat = argv[optind];
	} else if ((dat = getenv("USER")) == NULL) {
		fputs("amiint: failed getenv(\"USER\")\n");
		exit(1);
	}
	Noversion = flagC;
	Quiet = flagQ;

	signal(SIGHUP, die);
	signal(SIGINT, die);
	signal(SIGTERM, die);

	EnableMemoryContext(1);

	if (!cinit(Buf, dat, (XID *)"\0\0\0\001\0") && !Noversion)
		elog(FATAL, "cinit failed");
	if (chdir(Buf) < 0)
                elog(FATAL, "chdir(\"%s\"): %m", Buf);

	AmiTransactionOverride(override);
	if (!cinit2()) {
		elog(FATAL, "cinit2 failed");
	}

	i = MAXATTR;
	dat = Blanks;
	while (i--)
		*dat++ = ' ';

	signal(SIGHUP, handle_warn);

	if (setjmp(Warn_restart) != NULL) {
		Warnings++;
		AbortCurrentTransaction();
/*		reldesc = NULL;		/* relations are freed after aborts */
	}
	for (;;) {
		StartTransactionCommand();

		/* removed 
		startmmgr(0);
		*/
		printf("> ");
		if (scanf("%1s", Buf) == EOF)
			cleanup();
		switch (Buf[0]) {
		case 'C':	
			createrel(); 
			break;
		case 'o':	
			openrel(); 
			break;
		case 'c':
			closerel();
			break;
		case 'p':
			if (!Quiet) {
				printrel();
			}
			break;
#ifdef	EBUG
		case 'r':
			randomprintrel();
			break;
#endif
		case 't':
			attrtype();
			break;
		case 'm':
			handletime();
			break;
		case 'i':
			inserttup();
			break;
		case '#':
			break;
		case '.':
			handledot();
			break;
#ifdef	EBUG
		case '=':
			ShowLock = !ShowLock;
			break;
		case 'I':
			inserttuplocked();
			break;
#endif
		case EOF:
			cleanup();
			break;
		default:
			fprintf(stderr, "Warning: unknown command '%c'.\n",
				Buf[0]);
		} 
		/* removed
		endmmgr(0);
		*/
		skipline();

		CommitTransactionCommand();
	}
 usage:
	fputs("Usage: amiint [-C] [-Q] [datname]\n", stderr);
	exit(1);

}


createrel()
{
	extern	Relation	amcreatr();

	if (scanf("%s", relname) != 1) {
		fprintf(stderr, "Error: failed to read relation name to create\n.");
		err();
	}

/*
	if (RelationOpenContext == NULL) {
		(void)newcontext();
		initmmgr();
		RelationOpenContext = topcontext();
	}
	(void)switchcontext(RelationOpenContext);
	startmmgr(0);
*/
		
	printf("Amcreatr: relation %s.\n", relname);
	if ((numattr == 0) || (attrtypes == NULL)) {
		fprintf(stderr, "Warning: must define attributes before creating rel.\n");
		fprintf(stderr, "         relation not created.\n");
	} else {
		reldesc = amcreatr(relname, numattr, attrtypes);
		if (reldesc == (Relation)NULL) {
			fprintf(stderr, "Warning: cannot create relation %s.\n", relname);
			fprintf(stderr, "         Probably should delete old %s.\n", relname);
		}
	}
/*
	(void)topcontext();
*/
}

openrel()
{
	int		i;
	struct	typmap	**app;
	Relation	rdesc;
	HeapScan	sdesc;
	HeapTuple	tup;
	extern	char	TYPE_R[];
	Relation	amopenr();
	extern		amclose();
	HeapScan	ambeginscan();
	extern		amendscan();
	HeapTuple	amgetnext();
	extern		pfree();


	if (scanf("%s", relname) != 1) {
		fprintf(stderr, "Error: failed to read relation name to open\n.");
		err();
	}

/*
	if (RelationOpenContext == NULL) {
		(void)newcontext();
		initmmgr();
		RelationOpenContext = topcontext();
	}
	(void)switchcontext(RelationOpenContext);
*/

	if (Typ == (struct typmap **)NULL) {
		/* removed 
		startmmgr(0);
		*/
		rdesc = amopenr(TYPE_R);
		sdesc = ambeginscan(rdesc, 0, DefaultTimeRange, 0,
			(ScanKey)NULL);
		for (i = 0; PointerIsValid(tup =
				amgetnext(sdesc, 0, (Buffer *)NULL)); i++)
			;
		amendscan(sdesc);
		app = Typ = ALLOC(struct typmap *, i + 1);
		while (i-- > 0)
			*app++ = ALLOC(struct typmap, 1);
		*app = (struct typmap *)NULL;
		sdesc = ambeginscan(rdesc, 0, DefaultTimeRange, (ScanKey)NULL);
		app = Typ;
		while (PointerIsValid(tup =
				amgetnext(sdesc, 0, (Buffer *)NULL))) {
			(*app)->am_oid = tup->t_oid;
			bcopy((char *)GETSTRUCT(tup), (char *)&(*app++)->am_typ,
				sizeof (*app)->am_typ);
		}
		amendscan(sdesc);
		amclose(rdesc);
		/* removed
		(void)endmmgr(NULL);
		*/
	}
	if (reldesc != NULL) {
/*
		(void)topcontext();
*/
		closerel();
/*
		(void)switchcontext(RelationOpenContext);
*/
	}
/*
	startmmgr(0);
*/

	printf("Amopen: relation %s.\n", relname);
	reldesc = amopenr(relname);
	numattr = reldesc->rd_rel->relnatts;
	for (i = 0; i < numattr; i++) {
		if (attrtypes[i] == NULL) {
			attrtypes[i] = aalloc();
		}
		bcopy((char *)reldesc->rd_att.data[i], (char *)attrtypes[i],
			(int)sizeof *attrtypes[0]);
	}

/*
	(void)topcontext();
*/
}

closerel()
{
	extern	amclose();

	if (reldesc == NULL) {
		fprintf(stderr, "Warning: no opened relation to close.\n");
	} else {
/*
		(void)switchcontext(RelationOpenContext);
*/
		printf("Amclose: relation %s.\n", relname);
		amclose(reldesc);
		reldesc = (Relation)NULL;
/*
		resetmmgr();
		(void)topcontext();
*/
	}
}


destroyrel()
{
	char		destname[80];
	extern		amdestroy();

	if (scanf("%s", destname) != 1) {
		fprintf(stderr, "Error: failed to read relation name to destroy\n.");
		err();
	} else {
		printf("Amdestroy: relation %s.\n", destname);
		amdestroy(destname);
	}
}


printrel()
{
	HeapTuple	tuple;
	HeapScan	scandesc;
	int		i;
	Buffer		b;
	HeapScan	ambeginscan();
	HeapTuple	amgetnext();

	if (reldesc == NULL) {
		fprintf(stderr, "Warning: need to open relation to print.\n");
		return;
	}
	/* print the name of the attributes in the relation */
	printf("Relation %s:  ", relname);
	printf("[ ");
	for (i=0; i < reldesc->rd_rel->relnatts; i++)
		printf("%s ", &reldesc->rd_att.data[i]->attname);
	printf("]\n\n");
	/* removed 
	startmmgr(1);	
	*/
	/* print the tuples in the relation */
	scandesc = ambeginscan(reldesc, 0, StandardTimeRange, (unsigned)0,
		(ScanKey)NULL);
	while ((tuple = amgetnext(scandesc, 0, &b)) != NULL) {
		showtup(tuple, b, reldesc);
	}
	amendscan(scandesc);
	/* removed
	endmmgr(NULL);
	*/
	printf("\nEnd of relation\n");
}


#ifdef	EBUG
randomprintrel()
{
	HeapTuple	tuple;
	HeapScan	scandesc;
	Buffer		buffer;
	int		i, j, numattr, typeindex;
	int		count;
	int		mark = 0;
	static bool	isInitialized = false;
	HeapTuple	amgetnext();
	HeapScan	ambeginscan();
	extern		srandom();
	long		random();
	long		time();

	/* removed 
	startmmgr(0);
	*/
	if (reldesc == NULL) {
		fprintf(stderr, "Warning: need to open relation to (r) print.\n");
	} else {
		/* print the name of the attributes in the relation */
		printf("Relation %s:  ", relname);
		printf("[ ");
		for (i=0; i<reldesc->rd_rel->relnatts; i++) {
			printf("%s ", &reldesc->rd_att.data[i]->attname);
		}
		printf("]\nWill display %d tuples in a slightly random order\n\n",
			count = 64);
		/* print the tuples in the relation */
		if (!isInitialized) {
			srandom((int)time(0));
			isInitialized = true;
		}
		scandesc = ambeginscan(reldesc, random()&01, StandardTimeRange,
			0, (ScanKey)NULL);
		numattr = reldesc->rd_rel->relnatts;
		while (count-- != 0) {
			if (!(random() & 0xf)) {
				printf("\tRESTARTING SCAN\n");
				amrescan(scandesc, random()&01, (ScanKey)NULL);
				mark = 0;
			}
			if (!(random() & 0x3))
				if (mark) {
					printf("\tRESTORING MARK\n");
					amrestrpos(scandesc);
					mark &= random();
				} else {
					printf("\tSET MARK\n");
					ammarkpos(scandesc);
					mark = 0x1;
				}
			if (!PointerIsValid(tuple =
					amgetnext(scandesc, !(random() & 0x1),
						&buffer))) {
				puts("*NULL*");
				continue;
			}
			showtup(tuple, buffer, reldesc);
		}
		puts("\nDone");
		amendscan(scandesc);
	}
	/* removed
	endmmgr(NULL);
	*/
}
#endif

showtup(tuple, buffer, relation)
	HeapTuple	tuple;
	Buffer		buffer;
	Relation	relation;
{
	char		*value, *fmgr(), *amgetattr(), *abstimeout();
	Boolean		isnull;
	struct	typmap	**app;
	int		i, typeindex;

	value = (char *)amgetattr(tuple, buffer, ObjectIdAttributeNumber,
		(struct attribute **)NULL, &isnull);
	if (isnull) {
		printf("*NULL* < ");
	} else {
		printf("%ld < ", (long)value);
	}
	for (i = 0; i < numattr; i++) {
		value = (char *)amgetattr(tuple, buffer, 1 + i,
			&reldesc->rd_att.data[0], &isnull);
		if (isnull) {
			printf("<NULL> ");
		} else if (Typ != (struct typmap **)NULL) {
			app = Typ;
			while (*app != NULL && (*app)->am_oid !=
					reldesc->rd_att.data[i]->atttypid) {
				app++;
			}
			printf("%s ", value =
				fmgr((*app)->am_typ.typoutput, value));
			pfree(value);
		} else {
			typeindex = reldesc->rd_att.data[i]->atttypid -
				FIRST_TYPE_OID;
			printf("%s ", value =
				fmgr(Procid[typeindex][(int) Q_OUT], value));
			pfree(value);
		}
	}
	printf(">\n");
	if (ShowTime) {
		printf("\t[");
		value = amgetattr(tuple, buffer,
			MinAbsoluteTimeAttributeNumber,
			&reldesc->rd_att.data[0], &isnull);
		if (isnull) {
			printf("{*NULL*} ");
		} else if (TimeIsValid((Time)value)) {
			showtime((Time)value);
		}

		value = amgetattr(tuple, buffer, MinCommandIdAttributeNumber,
			&reldesc->rd_att.data[0], &isnull);
		if (isnull) {
			printf("(*NULL*,");
		} else {
			printf("(%u,", (CommandId)value);
		}

		value = amgetattr(tuple, buffer,
			MinTransactionIdAttributeNumber,
			&reldesc->rd_att.data[0], &isnull);
		if (isnull) {
			printf("*NULL*),");
		} else if (!TransactionIdIsValid((TransactionId)value)) {
			printf("-),");
		} else {
			printf("%s)",
				TransactionIdFormString((TransactionId)value));
			if (!TransactionIdDidCommit((TransactionId)value)) {
				if (TransactionIdDidAbort(
						(TransactionId)value)) {
					printf("*A*");
				} else {
					printf("*InP*");
				}
			}
			value = (char *)TransactionIdGetCommitTime(
				(TransactionId)value);
			if (!TimeIsValid((Time)value)) {
				printf("{-},");
			} else {
				showtime((Time)value);
				printf(",");
			}
		}

		value = amgetattr(tuple, buffer,
			MaxAbsoluteTimeAttributeNumber,
			&reldesc->rd_att.data[0], &isnull);
		if (isnull) {
			printf("{*NULL*} ");
		} else if (TimeIsValid((Time)value)) {
			showtime((Time)value);
		}

		value = amgetattr(tuple, buffer, MaxCommandIdAttributeNumber,
			&reldesc->rd_att.data[0], &isnull);
		if (isnull) {
			printf("(*NULL*,");
		} else {
			printf("(%u,", (CommandId)value);
		}

		value = amgetattr(tuple, buffer,
			MaxTransactionIdAttributeNumber,
			&reldesc->rd_att.data[0], &isnull);
		if (isnull) {
			printf("*NULL*)]\n");
		} else if (!TransactionIdIsValid((TransactionId)value)) {
			printf("-)]\n");
		} else {
			printf("%s)",
				TransactionIdFormString((TransactionId)value));
			value = (char *)TransactionIdGetCommitTime(
				(TransactionId)value);
			if (!TimeIsValid((Time)value)) {
				printf("{-}]\n");
			} else {
				showtime((Time)value);
				printf("]\n");
			}
		}
	}
#ifdef	EBUG
	if (ShowLock) {
		char	*lock;

		lock = amgetattr(tuple, buffer, RuleLockAttributeNumber,
			(struct attribute **)NULL, &isnull);
		if (isnull) {
			printf("\t<NULL>\n");
		} else {
			printf("\t");
			fflush(stdout);
			write(fileno(stdout), lock, psize(lock));
			printf("\n");
		}
	}
#endif
}

showtime(time)
	Time	time;
{
	extern char	*abstimeout();

	Assert(TimeIsValid(time));

	printf("{%d=%s}", time, abstimeout(time));
}

attrtype()
{
	int		attnum;
	int		attlen;
	char		name[16], type[20];
	TYPE		t;

	if (reldesc != NULL) {
		fputs("Warning: no open relations allowed with 't' command.\n",
			stderr);
		closerel();
	}
	if (scanf("%d", &numattr) != 1) {
		fprintf(stderr, "Error: 't' and '.A' must be followed by the number of attributes.\n");
		err();
	}
	if (numattr > MAXATTR) {
		fprintf(stderr, "Error: max. number of attributes is %d.\n", MAXATTR);
		err();
	}
	for (attnum = 0; attnum < numattr; attnum++) {
		if (scanf("%s %s", name, type) != 2) {
			fputs("Error: cannot read <attrname atttype>.", stderr);
			fputs("Please retype all.\n", stderr);
			err();
		}
		t = (TYPE)gettype(type);
		if (attrtypes[attnum] == (struct attribute *)NULL)
			attrtypes[attnum] = aalloc();
		if (Typ != (struct typmap **)NULL) {
			attrtypes[attnum]->atttypid = Ap->am_oid;
			strncpy(attrtypes[attnum]->attname, name, 16);
			printf("<%s %s> ", attrtypes[attnum]->attname, type);
			attrtypes[attnum]->attnum = 1 + attnum; /* fillatt */
			attlen = attrtypes[attnum]->attlen = Ap->am_typ.typlen;
			attrtypes[attnum]->attbyval = Ap->am_typ.typbyval;
		} else {
			attrtypes[attnum]->atttypid = Procid[(int)t][(int)Q_OID];
			strncpy(attrtypes[attnum]->attname,name, 16);
			printf("<%s %s> ", attrtypes[attnum]->attname, type);
			attrtypes[attnum]->attnum = 1 + attnum; /* fillatt */
			attlen = attrtypes[attnum]->attlen =
				Procid[(int)t][(int)Q_LEN]; /* fillatt */
			attrtypes[attnum]->attbyval = (attlen == 1) ||
				(attlen == 2) || (attlen == 4);
		}
	}
	/* fillatt(numattr, attrtypes); replaced by inline code */
	putchar('\n');
}


inserttup()
{
	int		i, typeindex;
	OID		oid;
	char		*prt;
	struct	typmap	**app;
	HeapTuple	tuple;
	char		value[80];
	extern	char	Blanks[];
	HeapTuple	formtuple();
	RuleLock	aminsert();
	char		*fmgr();

	if (reldesc == (Relation)NULL) {
		fprintf(stderr, "Error: must open/create relation before inserting tuples.\n");
		err();
	}
	/* removed 
	startmmgr(0);
	*/
	if (scanf("%ld", &oid) != 1) {
		fprintf(stderr, "Error: could not read OID value.\n");
		err();
	}
	if (oid != (OID)0)
		printf("tuple %d < ", oid);
	else
		printf("tuple < ");
	for (i=0; i < numattr; i++) {
		if (scanf("%s", value) != 1) {
			fprintf(stderr, "Error: cannot read attribute value.\n");
			err();
		} else if (Typ != (struct typmap **)NULL) {
			app = Typ;
			while (app != NULL && (*app)->am_oid !=
					reldesc->rd_att.data[i]->atttypid)
				app++;
			values[i] = fmgr((*app)->am_typ.typinput, value);
			printf("%s ", prt =
				fmgr((*app)->am_typ.typoutput, values[i]));
			pfree(prt);
		} else {
			typeindex = attrtypes[i]->atttypid - FIRST_TYPE_OID;
			values[i] = fmgr(Procid[typeindex][(int)Q_IN], value);
			printf("%s ", prt =
			       fmgr(Procid[typeindex][(int) Q_OUT], values[i]));
			pfree(prt);
		}
	}
	printf(">\n");
	tuple = formtuple(numattr, attrtypes, values, Blanks);
	if (oid != (OID)0) {
		ENABLE_BOOTSTRAP();
		tuple->t_oid = oid;
	}
	aminsert(reldesc, (HeapTuple)tuple, (double *)NULL);
	DISABLE_BOOTSTRAP();
	pfree(tuple);
	/* removed
	endmmgr(NULL);
	*/
}

#ifdef	EBUG

inserttuplocked()
{
	int		i, typeindex;
	OID		oid;
	char		*prt;
	struct	typmap	**app;
	HeapTuple	tuple;
	char		value[80];
	extern	char	Blanks[];
	HeapTuple	formtuple();
	RuleLock	aminsert();
	char		*fmgr();

	if (reldesc == (Relation)NULL) {
		fprintf(stderr, "Error: must open/create relation before inserting tuples.\n");
		err();
	}
	/* removed
	startmmgr(0);
	*/
	if (scanf("%ld", &oid) != 1) {
		fprintf(stderr, "Error: could not read OID value.\n");
		err();
	}
	if (oid != (OID)0)
		printf("tuple %d < ", oid);
	else
		printf("tuple < ");
	for (i=0; i < numattr; i++) {
		if (scanf("%s", value) != 1) {
			fprintf(stderr, "Error: cannot read attribute value.\n");
			err();
		} else if (Typ != (struct typmap **)NULL) {
			app = Typ;
			while (app != NULL && (*app)->am_oid !=
					reldesc->rd_att.data[i]->atttypid)
				app++;
			values[i] = fmgr((*app)->am_typ.typinput, value);
			printf("%s ", prt =
				fmgr((*app)->am_typ.typoutput, values[i]));
			pfree(prt);
		} else {
			typeindex = attrtypes[i]->atttypid - FIRST_TYPE_OID;
			values[i] = fmgr(Procid[typeindex][(int)Q_IN], value);
			printf("%s ", prt =
			       fmgr(Procid[typeindex][(int) Q_OUT], values[i]));
			pfree(prt);
		}
	}
	printf("> ");
	if (scanf("%s", value) != 1) {
		fprintf(stderr, "Error: cannot read lock value.\n");
		err();
	} else {
		int	len = strlen(value);

		prt = palloc(len);
		bcopy(value, prt, len);
	}
	printf("\n");
	tuple = formtuple(numattr, attrtypes, values, Blanks);
	HeapTupleSetRuleLock(tuple, InvalidBuffer, prt);
	if (oid != (OID)0) {
		ENABLE_BOOTSTRAP();
		tuple->t_oid = oid;
	}
	aminsert(reldesc, (HeapTuple)tuple, (double *)NULL);
	DISABLE_BOOTSTRAP();
	pfree(prt);
	pfree(tuple);
	/* removed
	endmmgr(NULL);
	*/
}
#endif

handledot()
{
	char		destname[80], destname2[80], destname3[80];
	Relation	oldrel, newrel;
	extern	char	Buf[];
	Relation	amopenr();
	extern		amclose();
	extern		amcreate(), amdestroy();
	extern		psort();
	extern		openrel(), closerel();

	if (scanf("%1s", Buf) == EOF) {
		fputs("Warning: prematurely ended final dot command.\n",
			stderr);
		cleanup();
	}
	if (reldesc != NULL) {
		fputs("Warning: no open relations allowed with dot commands.\n",
			stderr);
		closerel();
	}
	switch (Buf[0]) {
	case 'C':
		if (scanf("%s", destname) != 1) {
			fprintf(stderr, "Error: failed to read relation name to create.\n");
			err();
		}
		printf("Amcreate: relation %s.\n", destname);
		if ((numattr == 0) || (attrtypes == NULL))
			fputs("Warning: relation has no attributes.\n", stderr);
		amcreate(destname, 'n', numattr, attrtypes);
		break;
	case 'D':
		if (scanf("%s", destname) != 1) {
			fprintf(stderr, "Error: failed to read relation name to destroy.\n");
			err();
		} else {
			printf("Destroy: relation %s.\n", destname);
			amdestroy(destname);
		}
		break;
#ifdef	notdef
	case 'A':
		if (scanf("%s", destname) != 1) {
			fprintf(stderr, "Error: failed to read relation name for adding attributes\n.");
			err();
		}
		attrtype();
		addattribute(destname, numattr, attrtypes);
		break;
#endif
	case 'R':
		if (scanf("%1s", Buf) == EOF) {
			fputs("Error: '.R' command ended prematurely.\n",
				stderr);
			cleanup();
		}
		if (Buf[0] == 'R') {
			if (scanf("%s %s", destname, destname2) != 2) {
				fputs("Error: failed to read old ", stderr);
				fputs("and new relation names.\n", stderr);
				err();
			}
			printf("Renamerel: %s to relation %s.\n", destname, destname2);
			renamerel(destname, destname2);
		} else if (Buf[0] == 'A') { /* renameatt */
			if (scanf("%s %s %s", destname, destname2, destname3) != 3) {
				fprintf(stderr, "Error: failed to read relation and old and new attribute names.\n");
				err();
			}
			printf("Renameatt: from %s to %s.\n", destname2, destname3);
			renameatt(destname, destname2, destname3);
		} else {
			fprintf(stderr, "Error: unknown command '.R%c'.",
				Buf[0]);
			err();
		}
		break;
/*	case 'S':				/* Does not work yet */
/*
		if (scanf("%s %s", destname, destname2) != 2) {
			fputs("Error: failed to read old ", stderr);
			fputs("and new relation names.\n", stderr);
			err();
		}
		startmmgr(0);
		oldrel = amopenr(destname);
		amcreate(destname2, 'n', numattr, attrtypes);
		newrel = amopenr(destname2);
		psort(oldrel, newrel, numattr, attrtypes);
		amclose(oldrel);
		amclose(newrel);
		endmmgr(NULL);
		break;
*/
	case 'I':
		handleindex();
		break;
	default:
		fprintf(stderr, "Warning: unknown command '.%c'.\n", Buf[0]);
	}
}

handleindex()
{
	int	i;
	int	numberOfAttributes;
	int16	*attributeNumber;
	char	**xclass;
	char	heapName[80];
	char	indexName[80];
	char	accessMethodName[80];

	if (scanf("%s %s %s", heapName, indexName, accessMethodName) != 3) {
		fputs("Error: failed to read heap relation,", stderr);
		fputs(" index relation, and", stderr);
		fputs(" access method names.\n", stderr);
		err();
	}
	if (scanf("%d", &numberOfAttributes) != 1) {
		fputs("Error: failed to read number of attributes\n", stderr);
		err();
	}
	attributeNumber = (int16 *)palloc(numberOfAttributes *
		sizeof *attributeNumber);
	xclass = (char **)palloc(numberOfAttributes * sizeof *xclass);

	for (i = 0; i < numberOfAttributes; i += 1) {
		if (scanf("%hd", &attributeNumber[i]) != 1) {
			fputs("Error: failed to read attribute number\n",
				stderr);
			err();
		}
		xclass[i] = palloc(80);
		if (scanf("%s", xclass[i]) != 1) {
			fputs("Error: failed to read class name\n", stderr);
			err();
		}
	}
	DefineIndex(heapName, indexName, accessMethodName, numberOfAttributes,
		attributeNumber, xclass, 0, 0);
}

handletime()
{
	int	numberOfTimes;
	char	firstTime[80];
	char	secondTime[80];
	Time	time1;
	Time	time2;

	if (scanf("%d", &numberOfTimes) != 1) {
		fputs("Error: failed to read number of time fields\n", stderr);
		err();
	}
	if (numberOfTimes < -1 || numberOfTimes > 2) {
		elog(WARN,
			"number of time fields (%d) is not -1, 0, 1, or 2\n",
			numberOfTimes);
	} else if (numberOfTimes == -1) {
		ShowTime = !ShowTime;
		return;
	} else if (numberOfTimes == 0) {
		StandardTimeRange = DefaultTimeRange;
		puts("Time range reset to \"now\"");
	} else if (numberOfTimes == 1) {
		if (scanf("%[^\n]", firstTime) != 1) {
			fputs("Error: failed to read time\n", stderr);
			err();
		}
		time1 = abstimein(firstTime);
		printf("*** You entered \"%s\"", firstTime);
		if (time1 == INVALID_ABSTIME) {
			printf(" which is INVALID (time range unchanged).\n");
		} else {
			printf(" with representation %d.\n", time1);
			bcopy((char *)TimeFormSnapshotTimeRange(time1),
				(char *)&StandardTimeRangeSpace,
				sizeof StandardTimeRangeSpace);
			StandardTimeRange = (TimeRange)&StandardTimeRangeSpace;
		}
	} else {	/* numberOfTimes == 2 */
		if (scanf("%[^,],%[^\n]", firstTime, secondTime) != 2) {
			fputs("Error: failed to read both times\n", stderr);
			err();
		}
		printf("*** You entered \"%s\" and \"%s\"\n", firstTime,
			secondTime);
		time1 = abstimein(firstTime);
		time2 = abstimein(secondTime);
		if (time1 == INVALID_ABSTIME) {
			time1 = InvalidTime;
			if (time2 == INVALID_ABSTIME) {
				time2 = InvalidTime;
				printf("*** range is [,].\n");
			} else {
				printf("*** range is [,%d].\n", time2);
			}
		} else {
			if (time2 == INVALID_ABSTIME) {
				time2 = InvalidTime;
				printf("*** range is [%d,].\n", time1);
			} else {
				printf("*** range is [%d,%d].\n", time1, time2);
			}
		}
		bcopy(TimeFormRangedTimeRange(time1, time2),
			(char *)&StandardTimeRangeSpace,
			sizeof StandardTimeRangeSpace);
		StandardTimeRange = (TimeRange)&StandardTimeRangeSpace;
	}
}

cleanup()
{
	static	int	beenhere = 0;
	extern		amclose();

	if (!beenhere)
		beenhere = 1;
	else {
		fputs("Memory manager fault: cleanup called twice.\n", stderr);
		exit(1);
	}
	puts("** clean up and exit **");
	if (reldesc != (Relation)NULL) {
/*
		(void)switchcontext(RelationOpenContext);
*/
		amclose(reldesc);
/*
		resetmmgr();
		(void)topcontext();
*/
	}
	CommitTransactionCommand();
	EnableMemoryContext(0);
	exit(Warnings);
}

gettype(type)
char *type;
{
	int		i;
	Relation	rdesc;
	HeapScan	sdesc;
	HeapTuple	tup;
	struct	typmap	**app;
	extern	char	TYPE_R[];
	Relation	amopenr();
	extern		amclose();
	HeapScan	ambeginscan();
	extern		amendscan();
	HeapTuple	amgetnext();
	extern		pfree();

	if (Typ != (struct typmap **)NULL) {
		for (app = Typ; *app != (struct typmap *)NULL; app++)
			if (strcmp((*app)->am_typ.typname, type) == 0) {
				Ap = *app;
				return((*app)->am_oid);
			}
	} else {
		for (i = 0; i <= (int)TY_LAST; i++) {
			if (strcmp(type, typestr[i]) == 0) {
				return(i);
			}
		}
		rdesc = amopenr(TYPE_R);
		sdesc = ambeginscan(rdesc, 0, DefaultTimeRange, 0,
			(ScanKey)NULL);
		for (i = 0; PointerIsValid(tup = amgetnext(sdesc, 0,
				(Buffer *)NULL)); i++) {
			;
		}
		amendscan(sdesc);
		app = Typ = ALLOC(struct typmap *, i + 1);
		while (i-- > 0)
			*app++ = ALLOC(struct typmap, 1);
		*app = (struct typmap *)NULL;
		sdesc = ambeginscan(rdesc, 0, DefaultTimeRange,
			(ScanKey)NULL);
		app = Typ;
		while (PointerIsValid(tup =
				amgetnext(sdesc, 0, (Buffer *)NULL))) {
			(*app)->am_oid = tup->t_oid;
			bcopy((char *)GETSTRUCT(tup), (char *)&(*app++)->am_typ,
				sizeof (*app)->am_typ);
		}
		amendscan(sdesc);
		amclose(rdesc);
		return(gettype(type));
	}
	fprintf(stderr, "Error: unknown type '%s'.\n", type);
	err();
}

struct attribute *
aalloc()
{
	struct attribute	*a = new(struct attribute);

	if (!PointerIsValid(a)) {
		fprintf(stderr, "Error: malloc failed.\n");
		err();
	}
	bzero((Pointer)a, sizeof *a);
	return (a);
}

err()
{
	cleanup();
	exit(1);
}

skipline()
{
	while (getchar() != '\n');
}

handle_warn()
{
	longjmp(Warn_restart);
}

/* exit gracefully */
die()
{
	exit(0);
}
