
/*
 * 
 * POSTGRES Data Base Management System
 * 
 * Copyright (c) 1988 Regents of the University of California
 * 
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for educational, research, and non-profit purposes and
 * without fee is hereby granted, provided that the above copyright
 * notice appear in all copies and that both that copyright notice and
 * this permission notice appear in supporting documentation, and that
 * the name of the University of California not be used in advertising
 * or publicity pertaining to distribution of the software without
 * specific, written prior permission.  Permission to incorporate this
 * software into commercial products can be obtained from the Campus
 * Software Office, 295 Evans Hall, University of California, Berkeley,
 * Ca., 94720 provided only that the the requestor give the University
 * of California a free licence to any derived software for educational
 * and research purposes.  The University of California makes no
 * representations about the suitability of this software for any
 * purpose.  It is provided "as is" without express or implied warranty.
 * 
 */



static	char	dumpbpages_c[] = "$Header: dumpbpages.c,v 1.1 89/01/17 05:57:54 cimarron Exp $";

#include <sys/file.h>
#include <stdio.h>
#include <strings.h>

#include "context.h"
#include "magic.h"

#include "c.h"
#include "os.h"
#include "clib.h"

#include "block.h"
#include "bufmgr.h"
#include "bufpage.h"
#include "htup.h"
#include "itemid.h"
#include "page.h"
#include "part.h"
#include "tim.h"
#include "xid.h"

#define DEFAULT_TYPE	'b'

char		*Progname;
/* int	Version; */
int		Type;
char		Buf[BLCKSZ];

/*
 * ItemPointerFormExternal --
 */
extern
String
ItemPointerFormExternal ARGS((
	ItemPointer	pointer
));

/*
 * TimeAndTransactionIdFormExternal --
 */
extern
String
TimeAndTransactionIdFormExternal ARGS((
	AbsouteTime	time,
	TransactionId	transactionId,
	CommandId	commandId
));

main(argc, argv)
int	argc;
char	*argv[];
{
	int		s;
	int		errors = 0;
	char		*cp;
	extern		dumprelation();

	Progname = rindex(argv[0], '/');
	Progname = (Progname != (char *)NULL) ? Progname + 1 : argv[0];
	Type = DEFAULT_TYPE;
	if (! --argc)
		dumprelation(fileno(stdin), "<stdin>");
	while (argc--) {
		argv++;
		if (**argv != '-') {
			if ((s = open(*argv, O_RDONLY, 00)) < 0) {
				perror(*argv);
				continue;
			}
			dumprelation(s, *argv);
			close(s);
			continue;
		}
		cp = *argv;
		if ((Type = *++*argv) == '\0' || *++*argv != '\0') {
			Type = DEFAULT_TYPE;
			errors++;
			fprintf(stderr, "%s: bad argument %s", Progname, cp);
			continue;
		}
	}
	if (errors)
		fprintf(stderr, "Usage: %s {[-(b|r|i)] relpath}+\n", Progname);
}

dumprelation(fd, path)
int	fd;
char	path[];
{
	int		nr, pageno = 0;
	int		someBlocks;
	extern		dumppage();

	someBlocks = 0;
	while ((nr = read(fd, Buf, sizeof Buf)) == sizeof Buf) {
		if (someBlocks) {
			putchar('\n');
		}
		DumpBlock(path, pageno++);
		someBlocks = 1;
	}
	if (nr > 0)
		fprintf(stderr, "%s: %d bytes after last block\n", path, nr);
}

DumpBlock(path, blockNumber)
	char	path[];
	int	blockNumber;
{
	PageSize	pageSize;
	int		pageNumber;
	Page		page;

	pageSize = PageGetPageSize((Page)Buf);

	printf("%s[block=%d]:pageSize=%d\n", path, blockNumber, pageSize);

	for (pageNumber = 0; pageNumber < sizeof Buf / pageSize;
			pageNumber += 1) {
		page = (Page)&Buf[pageNumber * pageSize];
		if (pageSize != PageGetPageSize(page)) {
			fprintf(stderr, "DumpBlock: page %d: pageSize %d\n",
				pageNumber, PageGetPageSize(page));
		}
		DumpPage(page, blockNumber, pageNumber);
	}
}	

DumpPage(page, blockNumber, pageNumber)
	Page	page;
	int	blockNumber;
	int	pageNumber;
{
	ItemId		lp;
	HeapTuple	tup;
	int		flags, i, nline;
	PagePartition	partition;
	ItemPointerData	pointerData;

	partition = CreatePagePartition(sizeof Buf, PageGetPageSize(page));

	printf("\t[subblock=%d]:lower=%d:upper=%d:special=%d\n", pageNumber,
		((PageHeader)page)->pd_lower, ((PageHeader)page)->pd_upper,
		((PageHeader)page)->pd_special);

	printf("\t:MaxOffsetIndex=%d:InternalFragmentation=%d\n",
		(int16)PageGetMaxOffsetIndex(page),
		PageGetInternalFragmentation(page));

	nline = 1 + (int16)PageGetMaxOffsetIndex(page);

	/* add printing of the specially allocated fields */
{
	int	i;
	char	*cp;

	i = PageGetSpecialSize(page);
	cp = PageGetSpecialPointer(page);

	printf("\t:SpecialData=");

	while (i > 0) {
		printf(" 0x%02x", *cp);
		cp += 1;
		i -= 1;
	}
	printf("\n");
}
	for (i = 0; i < nline; i++) {
		lp = ((PageHeader)page)->pd_linp + i;
		flags = (*lp).lp_flags;
		ItemPointerSet(&pointerData, partition, blockNumber, pageNumber,
			1 + i);
		printf("%s:off=%d:flags=0x%x:len=%d",
			ItemPointerFormExternal(&pointerData), (*lp).lp_off,
			flags, (*lp).lp_len);
		if (flags & LP_USED)
			printf(":USED");
		if (flags & LP_IVALID)
			printf(":IVALID");
		if (flags & LP_DOCNT) {
			ItemPointer	pointer;

			pointer = (ItemPointer)(uint16 *)
				((char *)page + (*lp).lp_off);
			
			printf(":DOCNT@%s", ItemPointerFormExternal(pointer));
		}
		if (flags & LP_CTUP)
			printf(":CTUP");
		if (flags & LP_LOCK)
			printf(":LOCK");
		putchar('\n');

		if (Type == 'r' && (flags & LP_USED) && !(flags & LP_CTUP) &&
				!(flags & LP_LOCK)) {

			tup = (HeapTuple)&((char *)page)[(*lp).lp_off];
			if (flags & LP_DOCNT) {
				tup = (HeapTuple)&(((char *)tup)[TCONTPAGELEN]);
			}

			printf("\tlen=%ld:ctid=%s:oid=%ld",
				tup->t_len,
				ItemPointerFormExternal(&tup->t_ctid),
				tup->t_oid);

			printf(":min=%s", TimeAndTransactionIdFormExternal(
				tup->t_tmin, tup->t_xmin, tup->t_cmin));
			printf(":max=%s", TimeAndTransactionIdFormExternal(
				tup->t_tmax, tup->t_xmax, tup->t_cmax));

			printf(":chain=%s:anchor=%s",
				ItemPointerFormExternal(&tup->t_chain),
				ItemPointerFormExternal(&tup->t_anchor));
			printf(":natts=%d:thoff=%d:vtype=`%c'\n", tup->t_natts,
				tup->t_hoff, tup->t_vtype);
		}
	}
}

String
ItemPointerFormExternal(pointer)
	ItemPointer	pointer;
{
	static char	itemPointerString[32];

	if (!ItemPointerIsValid(pointer)) {
		bcopy("<-,-,->", itemPointerString, sizeof "<-,-,->");
	} else {
		sprintf(itemPointerString, "<%lu,%u,%u>",
			ItemPointerGetBlockNumber(pointer),
			ItemPointerSimpleGetPageNumber(pointer),
			ItemPointerSimpleGetOffsetNumber(pointer));
	}

	return (itemPointerString);
}

String
TimeAndTransactionIdFormExternal(time, transactionId, commandId)
	AbsoluteTime	time;
	TransactionId	transactionId;
	CommandId	commandId;
{
	static char	external[64];

	if (!TransactionIdIsValid(transactionId)) {
		sprintf(external, "{t=%d,x=(-,-),c=%u}", time, commandId);
	} else {
		sprintf(external, "{t=%d,x=(%u,%lu),c=%u}", time,
			transactionId->data[0],
			*(uint32 *)&transactionId->data[1], commandId);
	}

	return (external);
}

void
elog(level, format)
	int	level;
	char	*format;
{
	fprintf(stderr, "elog(%d, %s) called\n", level, format);
/*
	exit(-1);
*/
}
	
void
AssertionFailed(assertionName, fileName, lineNumber)
	char	*assertionName;
	char	*fileName;
	int	lineNumber;
{
	if (assertionName == 0 || fileName == 0) {
		fprintf(stderr, "AssertionFailed: bad arguments\n");
	} else {
		fprintf(stderr,
			"AssertionFailed(\"%s\", File: \"%s\", Line: %d)\n",
			assertionName, fileName, lineNumber);
	}
/*
	exit(-1);
*/
}

/* Memory management replacement functions */

Pointer
palloc(size)
	Size	size;
{
	return (malloc(size));
}

void
pfree(pointer)
	Pointer	pointer;
{
	free(pointer);
}
