5 Commits

Author SHA1 Message Date
e3b9612db0 Update copyright date. 2014-06-10 13:24:38 -04:00
093effb3f8 Add .gitignore. 2014-06-10 13:10:11 -04:00
bbd992bc26 Preliminary updates for Postgres 9.3. 2013-06-06 18:33:16 +00:00
4f71071d5b Updates for latest Postgres 9.2 sources.
We no longer need pg_crc.c, and hence not a source tree, yay.
2012-03-12 16:08:33 +00:00
883c674f6f Preliminary support for SP-GiST indexes. 2011-12-18 00:11:29 +00:00
6 changed files with 263 additions and 110 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/pg_filedump.o
/pg_filedump

View File

@ -1,32 +1,27 @@
# View README.pg_filedump first
# note this must match macro in pg_filedump.h
FD_VERSION=9.1.0
# note this must match version macros in pg_filedump.h
FD_VERSION=9.3.0
CC=gcc
CFLAGS=-g -O -Wall -Wmissing-prototypes -Wmissing-declarations
# PGSQL MUST POINT TO pgsql SOURCE DIRECTORY
PGSQL=../../pgsql
# If working with a PG source directory, point PGSQL_INCLUDE_DIR to its
# src/include subdirectory. If working with an installed tree, point to
# the server include subdirectory, eg /usr/local/include/postgresql/server
PGSQL_INCLUDE_DIR=../../pgsql/src/include
CRC_SRC_DIR=${PGSQL}/src/backend/utils/hash
INCLUDE_DIR=${PGSQL}/src/include
DISTFILES= README.pg_filedump Makefile Makefile.contrib \
pg_filedump.h pg_filedump.c
all: pg_filedump
pg_filedump: pg_filedump.o pg_crc.o
${CC} ${CFLAGS} -o pg_filedump pg_filedump.o pg_crc.o
pg_filedump: pg_filedump.o
${CC} ${CFLAGS} -o pg_filedump pg_filedump.o
pg_filedump.o: pg_filedump.c
${CC} ${CFLAGS} -I${INCLUDE_DIR} pg_filedump.c -c
pg_crc.o: ${CRC_SRC_DIR}/pg_crc.c
${CC} ${CFLAGS} -I${INCLUDE_DIR} ${CRC_SRC_DIR}/pg_crc.c -c
${CC} ${CFLAGS} -I${PGSQL_INCLUDE_DIR} pg_filedump.c -c
dist:
rm -rf pg_filedump-${FD_VERSION} pg_filedump-${FD_VERSION}.tar.gz

View File

@ -1,7 +1,5 @@
PROGRAM = pg_filedump
OBJS = pg_filedump.o pg_crc.o
EXTRA_CLEAN = pg_crc.c
OBJS = pg_filedump.o
DOCS = README.pg_filedump
@ -15,6 +13,3 @@ top_builddir = ../..
include $(top_builddir)/src/Makefile.global
include $(top_srcdir)/contrib/contrib-global.mk
endif
pg_crc.c: $(top_srcdir)/src/backend/utils/hash/pg_crc.c
rm -f $@ && $(LN_S) $< .

View File

@ -2,7 +2,7 @@ pg_filedump - Display formatted contents of a PostgreSQL heap, index,
or control file.
Copyright (c) 2002-2010 Red Hat, Inc.
Copyright (c) 2011, PostgreSQL Global Development Group
Copyright (c) 2011-2014, PostgreSQL Global Development Group
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -36,22 +36,24 @@ corrupt, you need a method of forcing a block size.
Compile/Installation:
To compile pg_filedump, you will need to have a properly configured
PostgreSQL source tree for the appropriate PostgreSQL major version.
PostgreSQL source tree or complete install tree (with include files)
of the appropriate PostgreSQL major version.
There are two makefiles included in this package. Makefile is a
standalone makefile for pg_filedump. Alter the PGSQL variable to point
to the PostgreSQL source tree. Makefile.contrib can be used if this
package was untarred in the contrib directory of a PostgreSQL build tree.
There are two makefiles included in this package. Makefile is a standalone
makefile for pg_filedump. Alter its PGSQL_INCLUDE_DIR variable to point to
the PostgreSQL include files. Makefile.contrib can be used if this package
was untarred in the contrib directory of a PostgreSQL build tree.
make
make install (if in the contrib directory)
make install (if using Makefile.contrib)
It is also possible to use Makefile.contrib without being in the contrib
directory:
make -f Makefile.contrib USE_PGXS=1
This will not eliminate the need to have a complete source tree, though.
This method requires that the pg_config program be in your PATH, but should
not require any manual adjustments of the Makefile.
------------------------------------------------------------------------
@ -85,3 +87,6 @@ The following options are valid for control files:
-c Interpret the file listed as a control file
-f Display formatted content dump along with interpretation
-S Force block size to [blocksize]
In most cases it's recommended to use the -i and -f options to get
the most useful dump output.

View File

@ -3,7 +3,7 @@
* formatting heap (data), index and control files.
*
* Copyright (c) 2002-2010 Red Hat, Inc.
* Copyright (c) 2011, PostgreSQL Global Development Group
* Copyright (c) 2011-2014, PostgreSQL Global Development Group
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -24,6 +24,8 @@
#include "pg_filedump.h"
#include "utils/pg_crc_tables.h"
// Global variables for ease of use mostly
static FILE *fp = NULL; // File to dump or format
static char *fileName = NULL; // File name for display
@ -62,7 +64,7 @@ DisplayOptions (unsigned int validOptions)
printf
("\nVersion %s (for %s)"
"\nCopyright (c) 2002-2010 Red Hat, Inc."
"\nCopyright (c) 2011, PostgreSQL Global Development Group\n",
"\nCopyright (c) 2011-2014, PostgreSQL Global Development Group\n",
FD_VERSION, FD_PG_VERSION);
printf
@ -286,7 +288,7 @@ ConsumeOptions (int numOptions, char **options)
SET_OPTION (itemOptions, ITEM_DETAIL, 'i');
break;
// Interpret items as index values
// Interpret items as standard index values
case 'x':
SET_OPTION (itemOptions, ITEM_INDEX, 'x');
if (itemOptions & ITEM_HEAP)
@ -434,20 +436,29 @@ GetSpecialSectionType (Page page)
rc = SPEC_SECT_ERROR_BOUNDARY;
else
{
// we may need to examine last 2 bytes of page to identify index
uint16 *ptype = (uint16 *) (buffer + blockSize - sizeof(uint16));
specialSize = blockSize - specialOffset;
// If there is a special section, use its size to guess its
// contents
// contents, checking the last 2 bytes of the page in cases
// that are ambiguous. Note we don't attempt to dereference
// the pointers without checking bytesToFormat == blockSize.
if (specialSize == 0)
rc = SPEC_SECT_NONE;
else if (specialSize == MAXALIGN (sizeof (uint32)))
{
// If MAXALIGN is 8, this could be either a sequence or GIN
// If MAXALIGN is 8, this could be either a sequence or
// SP-GiST or GIN.
if (bytesToFormat == blockSize)
{
specialValue = *((int *) (buffer + specialOffset));
if (specialValue == SEQUENCE_MAGIC)
rc = SPEC_SECT_SEQUENCE;
else if (specialSize == MAXALIGN (sizeof (SpGistPageOpaqueData)) &&
*ptype == SPGIST_PAGE_ID)
rc = SPEC_SECT_INDEX_SPGIST;
else if (specialSize == MAXALIGN (sizeof (GinPageOpaqueData)))
rc = SPEC_SECT_INDEX_GIN;
else
@ -456,6 +467,12 @@ GetSpecialSectionType (Page page)
else
rc = SPEC_SECT_ERROR_UNKNOWN;
}
// SP-GiST and GIN have same size special section, so check
// the page ID bytes first.
else if (specialSize == MAXALIGN (sizeof (SpGistPageOpaqueData)) &&
bytesToFormat == blockSize &&
*ptype == SPGIST_PAGE_ID)
rc = SPEC_SECT_INDEX_SPGIST;
else if (specialSize == MAXALIGN (sizeof (GinPageOpaqueData)))
rc = SPEC_SECT_INDEX_GIN;
else if (specialSize > 2 && bytesToFormat == blockSize)
@ -463,15 +480,13 @@ GetSpecialSectionType (Page page)
// As of 8.3, BTree, Hash, and GIST all have the same size
// special section, but the last two bytes of the section
// can be checked to determine what's what.
uint16 ptype = *(uint16 *) (buffer + blockSize - sizeof(uint16));
if (ptype <= MAX_BT_CYCLE_ID &&
if (*ptype <= MAX_BT_CYCLE_ID &&
specialSize == MAXALIGN (sizeof (BTPageOpaqueData)))
rc = SPEC_SECT_INDEX_BTREE;
else if (ptype == HASHO_PAGE_ID &&
else if (*ptype == HASHO_PAGE_ID &&
specialSize == MAXALIGN (sizeof (HashPageOpaqueData)))
rc = SPEC_SECT_INDEX_HASH;
else if (ptype == GIST_PAGE_ID &&
else if (*ptype == GIST_PAGE_ID &&
specialSize == MAXALIGN (sizeof (GISTPageOpaqueData)))
rc = SPEC_SECT_INDEX_GIST;
else
@ -594,15 +609,15 @@ FormatHeader (Page page)
" Block: Size %4d Version %4u Upper %4u (0x%04hx)\n"
" LSN: logid %6d recoff 0x%08x Special %4u (0x%04hx)\n"
" Items: %4d Free Space: %4u\n"
" TLI: 0x%04x Prune XID: 0x%08x Flags: 0x%04x (%s)\n"
" Checksum: 0x%04x Prune XID: 0x%08x Flags: 0x%04x (%s)\n"
" Length (including item array): %u\n\n",
pageOffset, pageHeader->pd_lower, pageHeader->pd_lower,
(int) PageGetPageSize (page), blockVersion,
pageHeader->pd_upper, pageHeader->pd_upper,
pageLSN.xlogid, pageLSN.xrecoff,
(uint32) (pageLSN >> 32), (uint32) pageLSN,
pageHeader->pd_special, pageHeader->pd_special,
maxOffset, pageHeader->pd_upper - pageHeader->pd_lower,
pageHeader->pd_tli, pageHeader->pd_prune_xid,
pageHeader->pd_checksum, pageHeader->pd_prune_xid,
pageHeader->pd_flags, flagString,
headerBytes);
@ -687,10 +702,30 @@ FormatItemBlock (Page page)
formatAs = ITEM_INDEX;
else if (itemOptions & ITEM_HEAP)
formatAs = ITEM_HEAP;
else if (specialType != SPEC_SECT_NONE)
formatAs = ITEM_INDEX;
else
switch (specialType)
{
case SPEC_SECT_INDEX_BTREE:
case SPEC_SECT_INDEX_HASH:
case SPEC_SECT_INDEX_GIST:
case SPEC_SECT_INDEX_GIN:
formatAs = ITEM_INDEX;
break;
case SPEC_SECT_INDEX_SPGIST:
{
SpGistPageOpaque spgpo =
(SpGistPageOpaque) ((char *) page +
((PageHeader) page)->pd_special);
if (spgpo->flags & SPGIST_LEAF)
formatAs = ITEM_SPG_LEAF;
else
formatAs = ITEM_SPG_INNER;
}
break;
default:
formatAs = ITEM_HEAP;
break;
}
for (x = 1; x < (maxOffset + 1); x++)
{
@ -754,9 +789,16 @@ static void
FormatItem (unsigned int numBytes, unsigned int startIndex,
unsigned int formatAs)
{
// It is an index item, so dump the index header
static const char * const spgist_tupstates[4] = {
"LIVE",
"REDIRECT",
"DEAD",
"PLACEHOLDER"
};
if (formatAs == ITEM_INDEX)
{
// It is an IndexTuple item, so dump the index header
if (numBytes < SizeOfIptrData)
{
if (numBytes)
@ -779,9 +821,86 @@ FormatItem (unsigned int numBytes, unsigned int startIndex,
"Internal <%d>.\n", numBytes, (int) IndexTupleSize (itup));
}
}
else if (formatAs == ITEM_SPG_INNER)
{
// It is an SpGistInnerTuple item, so dump the index header
if (numBytes < SGITHDRSZ)
{
if (numBytes)
printf (" Error: This item does not look like an SPGiST item.\n");
}
else
{
// It is a heap item, so dump the heap header
SpGistInnerTuple itup = (SpGistInnerTuple) (&(buffer[startIndex]));
printf (" State: %s allTheSame: %d nNodes: %u prefixSize: %u\n\n",
spgist_tupstates[itup->tupstate],
itup->allTheSame,
itup->nNodes,
itup->prefixSize);
if (numBytes != itup->size)
printf (" Error: Item size difference. Given <%u>, "
"Internal <%d>.\n", numBytes, (int) itup->size);
else if (itup->prefixSize == MAXALIGN(itup->prefixSize))
{
int i;
SpGistNodeTuple node;
// Dump the prefix contents in hex and ascii
if ((blockOptions & BLOCK_FORMAT) &&
SGITHDRSZ + itup->prefixSize <= numBytes)
FormatBinary (SGITHDRSZ + itup->prefixSize, startIndex);
// Try to print the nodes, but only while pointer is sane
SGITITERATE(itup, i, node)
{
int off = (char *) node - (char *) itup;
if (off + SGNTHDRSZ > numBytes)
break;
printf (" Node %2u: Downlink: %u/%u Size: %d Null: %u\n",
i,
((uint32) ((node->t_tid.ip_blkid.bi_hi << 16) |
(uint16) node->t_tid.ip_blkid.bi_lo)),
node->t_tid.ip_posid,
(int) IndexTupleSize(node),
IndexTupleHasNulls(node) ? 1 : 0);
// Dump the node's contents in hex and ascii
if ((blockOptions & BLOCK_FORMAT) &&
off + IndexTupleSize(node) <= numBytes)
FormatBinary (IndexTupleSize(node), startIndex + off);
if (IndexTupleSize(node) != MAXALIGN(IndexTupleSize(node)))
break;
}
}
printf ("\n");
}
}
else if (formatAs == ITEM_SPG_LEAF)
{
// It is an SpGistLeafTuple item, so dump the index header
if (numBytes < SGLTHDRSZ)
{
if (numBytes)
printf (" Error: This item does not look like an SPGiST item.\n");
}
else
{
SpGistLeafTuple itup = (SpGistLeafTuple) (&(buffer[startIndex]));
printf (" State: %s nextOffset: %u Block Id: %u linp Index: %u\n\n",
spgist_tupstates[itup->tupstate],
itup->nextOffset,
((uint32) ((itup->heapPtr.ip_blkid.bi_hi << 16) |
(uint16) itup->heapPtr.ip_blkid.bi_lo)),
itup->heapPtr.ip_posid);
if (numBytes != itup->size)
printf (" Error: Item size difference. Given <%u>, "
"Internal <%d>.\n", numBytes, (int) itup->size);
}
}
else
{
// It is a HeapTuple item, so dump the heap header
int alignedSize = MAXALIGN (sizeof (HeapTupleHeaderData));
if (numBytes < alignedSize)
@ -814,7 +933,7 @@ FormatItem (unsigned int numBytes, unsigned int startIndex,
printf (" XMIN: %u XMAX: %u CID|XVAC: %u",
HeapTupleHeaderGetXmin(htup),
HeapTupleHeaderGetXmax(htup),
HeapTupleHeaderGetRawXmax(htup),
HeapTupleHeaderGetRawCommandId(htup));
if (infoMask & HEAP_HASOID)
@ -839,12 +958,14 @@ FormatItem (unsigned int numBytes, unsigned int startIndex,
strcat (flagString, "HASEXTERNAL|");
if (infoMask & HEAP_HASOID)
strcat (flagString, "HASOID|");
if (infoMask & HEAP_XMAX_KEYSHR_LOCK)
strcat (flagString, "XMAX_KEYSHR_LOCK|");
if (infoMask & HEAP_COMBOCID)
strcat (flagString, "COMBOCID|");
if (infoMask & HEAP_XMAX_EXCL_LOCK)
strcat (flagString, "XMAX_EXCL_LOCK|");
if (infoMask & HEAP_XMAX_SHARED_LOCK)
strcat (flagString, "XMAX_SHARED_LOCK|");
if (infoMask & HEAP_XMAX_LOCK_ONLY)
strcat (flagString, "XMAX_LOCK_ONLY|");
if (infoMask & HEAP_XMIN_COMMITTED)
strcat (flagString, "XMIN_COMMITTED|");
if (infoMask & HEAP_XMIN_INVALID)
@ -862,6 +983,8 @@ FormatItem (unsigned int numBytes, unsigned int startIndex,
if (infoMask & HEAP_MOVED_IN)
strcat (flagString, "MOVED_IN|");
if (infoMask2 & HEAP_KEYS_UPDATED)
strcat (flagString, "KEYS_UPDATED|");
if (infoMask2 & HEAP_HOT_UPDATED)
strcat (flagString, "HOT_UPDATED|");
if (infoMask2 & HEAP_ONLY_TUPLE)
@ -908,9 +1031,8 @@ FormatItem (unsigned int numBytes, unsigned int startIndex,
}
// On blocks that have special sections, we have to interpret the
// contents based on size of the special section (since there is
// no other way)
// On blocks that have special sections, print the contents
// according to previously determined special section type
static void
FormatSpecial ()
{
@ -1043,6 +1165,30 @@ FormatSpecial ()
}
break;
// SP-GIST index section
case SPEC_SECT_INDEX_SPGIST:
{
SpGistPageOpaque spgistSection = (SpGistPageOpaque) (buffer + specialOffset);
if (spgistSection->flags & SPGIST_META)
strcat (flagString, "META|");
if (spgistSection->flags & SPGIST_DELETED)
strcat (flagString, "DELETED|");
if (spgistSection->flags & SPGIST_LEAF)
strcat (flagString, "LEAF|");
if (spgistSection->flags & SPGIST_NULLS)
strcat (flagString, "NULLS|");
if (strlen (flagString))
flagString[strlen (flagString) - 1] = '\0';
printf (" SPGIST Index Section:\n"
" Flags: 0x%08x (%s)\n"
" nRedirection: %d\n"
" nPlaceholder: %d\n\n",
spgistSection->flags, flagString,
spgistSection->nRedirection,
spgistSection->nPlaceholder);
}
break;
// No idea what type of special section this is
default:
printf (" Unknown special section type. Type: <%u>.\n", specialType);
@ -1101,6 +1247,8 @@ FormatControl ()
{
unsigned int localPgVersion = 0;
unsigned int controlFileSize = 0;
time_t cd_time;
time_t cp_time;
printf
("\n<pg_control Contents> *********************************************\n\n");
@ -1157,6 +1305,10 @@ FormatControl ()
break;
}
/* convert timestamps to system's time_t width */
cd_time = controlData->time;
cp_time = checkPoint->time;
printf (" CRC: %s\n"
" pg_control Version: %u%s\n"
" Catalog Version: %u\n"
@ -1191,16 +1343,16 @@ FormatControl ()
controlData->catalog_version_no,
controlData->system_identifier,
dbState,
ctime (&(controlData->time)),
controlData->checkPoint.xlogid, controlData->checkPoint.xrecoff,
controlData->prevCheckPoint.xlogid, controlData->prevCheckPoint.xrecoff,
checkPoint->redo.xlogid, checkPoint->redo.xrecoff,
ctime (&(cd_time)),
(uint32) (controlData->checkPoint >> 32), (uint32) controlData->checkPoint,
(uint32) (controlData->prevCheckPoint >> 32), (uint32) controlData->prevCheckPoint,
(uint32) (checkPoint->redo >> 32), (uint32) checkPoint->redo,
checkPoint->ThisTimeLineID,
checkPoint->nextXidEpoch, checkPoint->nextXid,
checkPoint->nextOid,
checkPoint->nextMulti, checkPoint->nextMultiOffset,
ctime (&checkPoint->time),
controlData->minRecoveryPoint.xlogid, controlData->minRecoveryPoint.xrecoff,
ctime (&cp_time),
(uint32) (controlData->minRecoveryPoint >> 32), (uint32) controlData->minRecoveryPoint,
controlData->maxAlign,
controlData->floatFormat,
(controlData->floatFormat == FLOATFORMAT_VALUE ?

View File

@ -3,7 +3,7 @@
* formatting heap (data), index and control files.
*
* Copyright (c) 2002-2010 Red Hat, Inc.
* Copyright (c) 2011, PostgreSQL Global Development Group
* Copyright (c) 2011-2014, PostgreSQL Global Development Group
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -22,21 +22,22 @@
* Original Author: Patrick Macdonald <patrickm@redhat.com>
*/
#define FD_VERSION "9.1.0" /* version ID of pg_filedump */
#define FD_PG_VERSION "PostgreSQL 9.1.x" /* PG version it works with */
#define FD_VERSION "9.3.0" /* version ID of pg_filedump */
#define FD_PG_VERSION "PostgreSQL 9.3.x" /* PG version it works with */
#include "postgres.h"
#include <time.h>
#include <ctype.h>
#include "access/gin.h"
#include "access/gin_private.h"
#include "access/gist.h"
#include "access/hash.h"
#include "access/htup.h"
#include "access/htup_details.h"
#include "access/itup.h"
#include "access/nbtree.h"
#include "access/spgist_private.h"
#include "catalog/pg_control.h"
#include "storage/bufpage.h"
@ -61,8 +62,10 @@ static unsigned int itemOptions = 0;
typedef enum
{
ITEM_DETAIL = 0x00000001, // -i: Display interpreted items
ITEM_HEAP = 0x00000002, // -y: Blocks contain heap items
ITEM_INDEX = 0x00000004 // -x: Blocks contain index items
ITEM_HEAP = 0x00000002, // -y: Blocks contain HeapTuple items
ITEM_INDEX = 0x00000004, // -x: Blocks contain IndexTuple items
ITEM_SPG_INNER = 0x00000008, // Blocks contain SpGistInnerTuple items
ITEM_SPG_LEAF = 0x00000010 // Blocks contain SpGistLeafTuple items
}
itemSwitches;
@ -85,6 +88,7 @@ typedef enum
SPEC_SECT_INDEX_HASH, // Hash index info in special section
SPEC_SECT_INDEX_GIST, // GIST index info in special section
SPEC_SECT_INDEX_GIN, // GIN index info in special section
SPEC_SECT_INDEX_SPGIST, // SP-GIST index info in special section
SPEC_SECT_ERROR_UNKNOWN, // Unknown error
SPEC_SECT_ERROR_BOUNDARY // Boundary error
}