/*
 * testpsort.c --
 *	Polyphase merge sort test code.
 */

#include <stdio.h>

#include "c.h"

RcsId("$Header: /private/postgres/src/test/RCS/testpsort.c,v 1.9 1991/07/22 22:20:38 mao Exp $");

#include "aset.h"
#include "buf.h"
#include "catname.h"
#include "heapam.h"
#include "htup.h"
#include "log.h"
#include "oid.h"
#include "portal.h"	/* for {Start,End}PortalAllocMode */
#include "rel.h"
#include "relscan.h"
#include "skey.h"
#include "tqual.h"

#include "storage/smgr.h"

/*
 * DoSetSortParameters --
 *	Initializes the sort parameters.
 */
extern
void
DoSetSortParameters ARGS((
	void
));

/*
 * DoCreateNewRelation --
 *	Creates a result relation.
 */
extern
void
DoCreateNewRelation ARGS((
	void
));

/*
 * DoShowRelation --
 *	Displays the contents of a relation.
 */
extern
void
DoShowRelation ARGS((
	Relation	relation
));

/*
 * DoShowHeapTuple --
 *	Displays an heap tuple.
 */
extern
void
DoShowHeapTuple ARGS((
	HeapTuple	tuple,
	Buffer		buffer,
	Relation	relation
));

/*
 * DoShowAttributeValue --
 *	Displays an attribute value.
 */
extern
void
DoShowAttributeValue ARGS((
	char		*value,
	ObjectId	typeId
));

/*
 * DoQuit --
 *	Quit.
 */
extern
void
DoQuit ARGS((
	void
));

#define MAXKEYSIZE	16

static Relation		OldRelation;
static Relation		NewRelation;
static NameData		RelationNameData;
static ScanKeySize	NumberOfKeys;
static ScanKeyEntryData	KeyData[MAXKEYSIZE];
static ScanKey		Key = (ScanKey)KeyData;

TestMain()
{
	static	int			beenHere = 0;

	if (beenHere == 0) {
		beenHere = 1;

		StartTransactionCommand();
	} else {
		elog(FATAL, "testpsort: giving up!");
	}

	for (;;) {
		StartPortalAllocMode(StaticAllocMode);

		DoSetSortParameters();

		DoShowRelation(OldRelation);

		DoCreateNewRelation();

		psort(OldRelation, NewRelation, NumberOfKeys, Key);

		RelationCloseHeapRelation(OldRelation);

		setheapoverride(true);	/* XXX */
		DoShowRelation(NewRelation);
		setheapoverride(false);	/* XXX */

		RelationCloseHeapRelation(NewRelation);

		EndPortalAllocMode();

		CommitTransactionCommand();
		StartTransactionCommand();
	}
}

void
DoSetSortParameters()
{
	int		i;
	char		buf[120];

	printf("Please enter the name of an existant relation: ");
	if (scanf("%s", buf) < 1) {
		DoQuit();
	}
	strncpy(&RelationNameData, buf, 16);

	OldRelation = RelationNameOpenHeapRelation(&RelationNameData);

	printf("Please enter the name of an non-existant relation: ");
	if (scanf("%s", buf) < 1) {
		DoQuit();
	}
	strncpy(&RelationNameData, buf, 16);

	printf("Please enter the key size (<= %d): ", MAXKEYSIZE);
	if (scanf("%hd", &NumberOfKeys) < 1) {
		DoQuit();
	}
	if (NumberOfKeys < 1 || NumberOfKeys > MAXKEYSIZE) {
		fprintf(stderr, "Invalid key size %d\n", NumberOfKeys);
		exitpg(1);
	}

	printf("Please enter sets of attribute numbers, flags, and procedure ids\n");
	for (i = 0; i < NumberOfKeys; i += 1) {
		printf("Key %02d: ", i);
		if (scanf("%hd %hd %d", &KeyData[i].attributeNumber,
			&KeyData[i].flags, &KeyData[i].procedure) < 3) {
			DoQuit();
		}
	}
}

void
DoCreateNewRelation()
{
	RelationNameCreateHeapRelation(&RelationNameData, 'n',
		OldRelation->rd_rel->relnatts,
		DEFAULT_SMGR,
		RelationGetTupleDescriptor(OldRelation));
	setheapoverride(true);		/* XXX */
	NewRelation = RelationNameOpenHeapRelation(&RelationNameData);
	setheapoverride(false);		/* XXX */
}

void
DoShowRelation(relation)
	Relation	relation;
{
	HeapScanDesc	scan;
	HeapTuple	tuple;
	Buffer		buffer;

	printf("----START(%s)----\n", &relation->rd_rel->relname);

	scan = RelationBeginHeapScan(relation, 0, NowTimeQual, 0,
		(ScanKey)NULL);

	while (HeapTupleIsValid(tuple =
			HeapScanGetNextTuple(scan, 0, &buffer))) {

		DoShowHeapTuple(tuple, buffer, relation);
	}

	HeapScanEnd(scan);

	printf("----END(%s)----\n", &relation->rd_rel->relname);
}

void
DoShowHeapTuple(tuple, buffer, relation)
	HeapTuple	tuple;
	Buffer		buffer;
	Relation	relation;
{
	char		*value, *fmgr(), *amgetattr(), *abstimeout();
	Boolean		isnull;
	int		i, typeindex;

	printf("< ");

	for (i = 0; i < relation->rd_rel->relnatts; i++) {
		value = amgetattr(tuple, buffer, 1 + i,
			&relation->rd_att.data[0], &isnull);
		if (isnull) {
			printf("<NULL> ");
		} else {
			DoShowAttributeValue(value,
				relation->rd_att.data[i]->atttypid);
			printf(" ");
		}
	}
	printf(">\n");
}

void
DoShowAttributeValue(value, typeId)
	char		*value;
	ObjectId	typeId;
{
	HeapTuple		tuple;

	static struct catcache	*typeCache = NULL;
	extern HeapTuple	SearchSysCache();
	extern struct catcache	*InitSysCache();
	extern char		*fmgr();

	if (typeCache == NULL) {
		int	key = ObjectIdAttributeNumber;

		typeCache = InitSysCache(TypeRelationName, 1, &key);
	}

	tuple = SearchSysCache(typeCache, typeId);

	if (!HeapTupleIsValid(tuple)) {
		elog(WARN, "testbtree: unknown type #%ld\n", typeId);
	}
	value = fmgr(((struct type *)HeapTupleGetForm(tuple))->typoutput,
		value);
	printf("%s", value);
}

void
DoQuit()
{
	CommitTransactionCommand();

	printf("\nDone!\n");
	exitpg(0);
}
