/* * Written by Tomas Dosoudil * This file is distributed under BSD-style license. * */ #include #include #include #include #include "output.h" #include "pgdview.h" /* * print file number */ void PrintFileName(char *fileName, int numberOfFile) { printf("Filename: %s.%d\n", fileName, numberOfFile); } /* * page info * it prints number of page, tuples and free space * tuple format is: total(used/delete/unused) */ void PrintPageInfo(int pageNumber, int itemCount, int itemUsed, int itemDelete, Size freeSpace) { int unused; unused = itemCount - itemUsed - itemDelete; printf("Page: %4d\tTuples: %3d(%3d/%3d/%3d)\tFree Space: %4ld B\n", pageNumber, itemCount, itemUsed, itemDelete, unused, freeSpace); } /* * print pageheader */ void PrintPageHeader(PageHeader pageHeader) { printf("\tpd_lsn: %08X%08X\n", (pageHeader->pd_lsn).xlogid, (pageHeader->pd_lsn).xrecoff); printf("\t xlogid: %08X\n", (pageHeader->pd_lsn).xlogid); printf("\t xrecoff: %08X\n", (pageHeader->pd_lsn).xrecoff); printf("\tpd_tli: %08X\n", pageHeader->pd_tli); printf("\tpd_lower: %04X\n", pageHeader->pd_lower); printf("\tpd_upper: %04X\n", pageHeader->pd_upper); printf("\tpd_special: %04X\n", pageHeader->pd_special); printf("\tpd_pagesize_version: %04X\n", pageHeader->pd_pagesize_version); printf("\t Page size: %02X\n", (pageHeader->pd_pagesize_version & 0xFF00)); printf("\t Layout version: %02X\n", (pageHeader->pd_pagesize_version & 0x00FF)); } /* * print itempointer on position */ void PrintPageItemPointer(int index, ItemId *item) { printf("\t\tTuple: %3d\tOffset: %4X\tLength: %4X\tFlags: %02X ", index, ItemIdGetOffset(*item), ItemIdGetLength(*item), ItemIdGetFlags(*item)); if (ItemIdGetFlags(*item) == LP_USED) printf("(Used)\n"); else if (ItemIdGetFlags(*item) == LP_DELETE) printf("(Delete)\n"); else printf("(Unused)\n"); } /* * print header of tuple */ void PrintHeapTupleHeader(HeapTupleHeader tupleHeader) { printf("\t\t\tt_xmin: %08X\n", HeapTupleHeaderGetXmin(tupleHeader)); printf("\t\t\tt_xmax: %08X\n", HeapTupleHeaderGetXmax(tupleHeader)); printf("\t\t\tt_cmin: %08X\n", HeapTupleHeaderGetCmin(tupleHeader)); printf("\t\t\tt_xvac: %08X\n", HeapTupleHeaderGetXvac(tupleHeader)); /* * order of structures: * HeapTupleHeader -> ItemPointerData -> { BlockIdData -> { bi_hi, bi_lo }, ip_posid } */ printf("\t\t\tt_ctid: %04X%04X%04X\n", tupleHeader->t_ctid.ip_blkid.bi_hi, tupleHeader->t_ctid.ip_blkid.bi_lo, tupleHeader->t_ctid.ip_posid); printf("\t\t\tt_natts: %04X\n", tupleHeader->t_natts); printf("\t\t\tt_infomask: %04X\n", tupleHeader->t_infomask); /* show values in t_infomask */ if (tupleHeader->t_infomask) { if (_HeapTupleHasNulls(tupleHeader)) printf("\t\t\t HEAP_HASNULL\n"); if (_HeapTupleHasVarWidth(tupleHeader)) printf("\t\t\t HEAP_HASVARWIDTH\n"); if (_HeapTupleHasExternal(tupleHeader)) printf("\t\t\t HEAP_HASEXTERNAL\n"); if (_HeapTupleHasCompressed(tupleHeader)) printf("\t\t\t HEAP_HASCOMPRESSED\n"); if (_HeapTupleHasExtended(tupleHeader)) printf("\t\t\t HEAP_HASEXTENDED\n"); if (HeapTupleHasOid(tupleHeader)) printf("\t\t\t HEAP_HASOID\n"); if (HeapTupleHasUnlogged(tupleHeader)) printf("\t\t\t HEAP_XMAX_UNLOGGED\n"); if (HeapTupleHasXminCommitted(tupleHeader)) printf("\t\t\t HEAP_XMIN_COMMITTED\n"); if (HeapTupleHasXminInvalid(tupleHeader)) printf("\t\t\t HEAP_XMIN_INVALID\n"); if (HeapTupleHasXmaxCommitted(tupleHeader)) printf("\t\t\t HEAP_XMAX_COMMITTED\n"); if (HeapTupleHasXmaxInvalid(tupleHeader)) printf("\t\t\t HEAP_XMAX_INVALID\n"); if (HeapTupleHasMarkedUpdate(tupleHeader)) printf("\t\t\t HEAP_MARKED_FOR_UPDATE\n"); if (HeapTupleHasUpdated(tupleHeader)) printf("\t\t\t HEAP_UPDATED\n"); if (HeapTupleHasMovedOff(tupleHeader)) printf("\t\t\t HEAP_MOVED_OFF\n"); if (HeapTupleHasMovedIn(tupleHeader)) printf("\t\t\t HEAP_MOVED_IN\n"); if (HeapTupleHasMoved(tupleHeader)) printf("\t\t\t HEAP_MOVED\n"); } printf("\t\t\tt_hoff: %02X\n", tupleHeader->t_hoff); } /* * print tuple data * format is like in hexdump: offset data(2x8B) */ void PrintHeapTupleData(HeapTupleHeader tupleHeader, uint32 tupleOffset, uint32 tupleLength) { uint8 *userData; /* point to data */ uint32 userDataLen; /* data length */ uint32 dataOffset; /* data offset in page */ uint32 j; /* counter */ /* point to tuple data */ userData = (uint8*) tupleHeader; userData += tupleHeader->t_hoff; userDataLen = tupleLength - tupleHeader->t_hoff; dataOffset = tupleOffset + tupleHeader->t_hoff; printf("\t\t\t\t%04X | ", dataOffset); /* offset */ for (j = 0; j < userDataLen; j++) { if (((j % 8) == 0) && (j != 0)) printf(" "); if (((j % 16) == 0) && (j != 0)) printf("\n\t\t\t\t%04X | ", dataOffset + j); /* offset */ printf("%02X ", *userData); userData++; } printf("\n"); } void Usage(void) { printf("pgdview [-p [num] -i [num] [-tdf]] [-ch] { [-D db_path table_oid] | file_name }\n"); printf(" -p page\n"); printf(" -c page header\n"); printf(" -i item list\n"); printf(" -t tuple header\n"); printf(" -d tuple data\n"); printf(" -f follow ctid\n"); printf(" -D database path\n"); printf(" -h help\n"); printf("\nNumeral range\n"); printf(" Page starts from 0 and tuples from 1\n"); printf(" Possible values are num,..num,num..,num..num\n"); printf(" If parameter does not have argument then show all\n"); printf(" First page is default if parameter -p does not set\n"); printf("\nFollow ctid\n"); printf(" When you want to use follow ctid you must enter the page\n"); printf(" where item is stored and its number\n"); printf(" e.g pgdview -p 1 -i 1 -tf -D ./path filename\n"); printf(" Show first item and its tuple header on page one and make follow\n"); }