8 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
3551cfe252 Update for Postgres 9.1; add knowledge of some more flag bits;
improve Makefile to be able to build a release tarball.
2011-11-26 22:14:08 +00:00
2c9c61c841 Fix odd printout of hasnulls/hasvarwidths flags for index tuples.
Per a gripe some months ago from Alvaro.
2011-01-18 02:36:38 +00:00
ac96dfbaca Assorted adjustments to prepare pg_filedump for its new life.
Add PostgreSQL Global Development Group to the copyright notices, and
remove a couple of no-longer-appropriate references to Red Hat.
Unfortunately I can't undo Red Hat's choice of GPL licensing, but it is
what it is.

Also reduce the pain of version-stamping by coalescing references to the
version into one pair of macros, and removing not-especially-useful
change logs.  IMO the commit logs serve that purpose just as well.
2011-01-18 02:28:26 +00:00
7 changed files with 327 additions and 343 deletions

2
.gitignore vendored Normal file
View File

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

174
ChangeLog
View File

@ -1,174 +0,0 @@
2010-12-29 Tom Lane <tgl@redhat.com>
* pg_filedump.c, .h: Update version and copyright date for
PostgreSQL 9.0 (there aren't any on-disk layout changes in 9.0).
2009-07-08 Tom Lane <tgl@redhat.com>
* pg_filedump.c: Update for changes in pg_control contents in
PostgreSQL 8.4.
* pg_filedump.c, .h: Update version and copyright date.
2008-02-08 Tom Lane <tgl@redhat.com>
* pg_filedump.c: Updates for various representation changes in
PostgreSQL 8.3; in particular there is finally a trustworthy way
to tell apart the various types of index special space.
* pg_filedump.c, .h: Update version and copyright date.
2007-02-14 Tom Lane <tgl@redhat.com>
* pg_filedump.c, .h: Remove rtree support (gone in PostgreSQL 8.2)
and add GIN support. Other updates for changes in index special
section contents in 8.2.
* pg_filedump.c: Repair old bug that misreported header length by
4 bytes.
* pg_filedump.c, .h: Update version and copyright date.
2005-11-21 Tom Lane <tgl@redhat.com>
* pg_filedump.c, .h: Adjust to support PostgreSQL 8.1 tuple format
and control file layout.
* pg_filedump.c, .h: Update version and copyright date.
* Makefile.contrib: Update for PGXS changes.
2005-02-10 Tom Lane <tgl@redhat.com>
* pg_filedump.c, .h: Adjust to support PostgreSQL 8.0 tuple format.
* pg_filedump.c, .h: Update version and copyright date.
2003-09-29 Patrick Macdonald <patrickm@redhat.com>
* pg_filedump.c (GetSpecialSectionType): Distinguish between btree and
hash index pages using the hasho_filler field.
(FormatHeader): Verify index page header is btree before dumping meta
data.
(FormatSpecial): Format index areas based on precalculated special
section type.
* pg_filedump.h: Add distinct index special section types.
2003-05-30 Patrick Macdonald <patrickm@redhat.com>
* pg_filedump.c: Bumped version up to 3.0.
2003-04-17 Patrick Macdonald <patrickm@redhat.com>
* pg_filedump.c (DisplayOptions): Update version and copyright
date.
(FormatHeader): Display btree meta data as part of the header
if this is a btree meta page.
(FormatItem): Remove older version defines.
(FormatSpecial): Add new btree defines.
(FormatControl): Remove older version defines.
* pg_filedump.h: Update version and copyright date, remove older
version structure defines.
2003-04-17 Patrick Macdonald <patrickm@redhat.com>
* pg_filedump.c: Updated header, copyright and indentation.
* pg_filedump.h: ditto.
2002-12-18 Patrick Macdonald <patrickm@redhat.com>
* pg_filedump.c: Version 1.1 of the tool, moved
declarations to proper header,
(GetBlockSize): Cache block size locally,
(CreateDumpFileHeader): Increment the release minor,
(FormatHeader): Add block version number to output,
(FormatItem): Support new heap tuple layout,
(FormatControl): Support additional entries in the
control file.
* pg_filedump.h: New file.
* README.pg_filedump: Updated for version control.
2002-10-16 Patrick Macdonald <patrickm@redhat.com>
* rhdb-utils.build: Updated branch level.
2002-09-24 Andrew Overholt <overholt@redhat.com>
* rhdb-utils.build: Change cvsroot to reflect new server.
2002-09-11 Andrew Overholt <overholt@redhat.com>
* rhdb-utils.spec: Change release number to 1.
2002-07-29 Liam Stewart <liams@redhat.com>
* rhdb-utils.build: Tightened the cvs module so checkouts don't
take forever.
(get_cvs): Checkout instead of export.
(build): Call build_srpm to build SRPM.
2002-07-10 Liam Stewart <liams@redhat.com>
* rhdb-utils.build (build): Use rpmbuild instead of rpm; ignore
dependencies.
2002-07-08 Liam Stewart <liams@redhat.com>
* rhdb-utils.spec: Updated summary and description text. Bumped
release.
2002-07-04 Liam Stewart <liams@redhat.com>
* rhdb-utils.build: $download -> $downloaddir
* rhdb-utils.spec: New file.
* rhdb-utils.build: New file.
* rpm-extras/pg_filedump-crc.patch: New file.
* rpm-extras/pg_filedump-make.patch: New file.
2002-03-08 Patrick Macdonald <patrickm@redhat.com>
* pg_filedump.c (FormatItem): Remove EXTENDED,
add XMAX_COMMITED and XMAX_INVALID, add proper
t_bits[] processing, fix typo.
* Makefile.contrib: New file.
2002-03-04 Patrick Macdonald <patrickm@redhat.com>
* README.pg_filedump: sources merge.
2002-02-04 Patrick Macdonald <patrickm@redhat.com>
* pg_filedump.c: Add macro to set options and
flag duplicates, move copyright out of the
header block, use MAXALIGN when determining
special section size
* README.pg_filedump: New file.
2002-02-01 Patrick Macdonald <patrickm@redhat.com>
* pg_filedump.c: Alter copyright info to GPL.
* pg_filedump.c: Minor tweaks to printf() formatting,
(FormatItem): Add new parameter to receive the
formatting method.
(FormatItemBlock): Determine and pass the format
method to FormatItem().
2002-01-30 Patrick Macdonald <patrickm@redhat.com>
* pg_filedump.c: Added -B to valid control file
dump options.
* Makefile: Add -Wmissing-prototypes and
-Wmissing-declarations.
2002-01-29 Patrick Macdonald <patrickm@redhat.com>
* pg_filedump.c: Renamed from pgfiledump.c
2002-01-29 Patrick Macdonald <patrickm@redhat.com>
* pgfiledump.c: Scrubbed the code, added support
for CRC checking, improved readability, fixed
unsigned vs signed problems.
* Makefile: Added pg_crc.c to support CRC checks.
2002-01-28 Patrick Macdonald <patrickm@redhat.com>
* pgfiledump.c: Added FormatControl() to support
dumping of the PostgreSQL control file.
2002-01-25 Patrick Macdonald <patrickm@redhat.com>
* Makefile, pgfiledump.c: New file.

View File

@ -1,26 +1,34 @@
# View README.pg_filedump first # View README.pg_filedump first
# note this must match version macros in pg_filedump.h
FD_VERSION=9.3.0
CC=gcc CC=gcc
CFLAGS=-g -O -Wall -Wmissing-prototypes -Wmissing-declarations CFLAGS=-g -O -Wall -Wmissing-prototypes -Wmissing-declarations
INCLUDE=/usr/include/pgsql/server # 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
# PGSQL MUST POINT TO pgsql SOURCE DIRECTORY
PGSQL=../../../../postgres/pgsql
CRC_SRC=${PGSQL}/src/backend/utils/hash DISTFILES= README.pg_filedump Makefile Makefile.contrib \
CRC_INCLUDE=${PGSQL}/src pg_filedump.h pg_filedump.c
all: pg_filedump all: pg_filedump
pg_filedump: pg_filedump.o pg_crc.o pg_filedump: pg_filedump.o
${CC} ${CFLAGS} -o pg_filedump pg_filedump.o pg_crc.o ${CC} ${CFLAGS} -o pg_filedump pg_filedump.o
pg_filedump.o: pg_filedump.c pg_filedump.o: pg_filedump.c
${CC} ${CFLAGS} -I${INCLUDE} pg_filedump.c -c ${CC} ${CFLAGS} -I${PGSQL_INCLUDE_DIR} pg_filedump.c -c
pg_crc.o: ${CRC_SRC}/pg_crc.c dist:
${CC} ${CFLAGS} -I${CRC_INCLUDE} -I${INCLUDE} ${CRC_SRC}/pg_crc.c -c rm -rf pg_filedump-${FD_VERSION} pg_filedump-${FD_VERSION}.tar.gz
mkdir pg_filedump-${FD_VERSION}
cp -p ${DISTFILES} pg_filedump-${FD_VERSION}
tar cfz pg_filedump-${FD_VERSION}.tar.gz pg_filedump-${FD_VERSION}
rm -rf pg_filedump-${FD_VERSION}
clean: clean:
rm -rf *.o pg_filedump rm -f *.o pg_filedump

View File

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

View File

@ -1,20 +1,21 @@
pg_filedump - Display formatted contents of a PostgreSQL heap/index/control pg_filedump - Display formatted contents of a PostgreSQL heap, index,
file. or control file.
Copyright (c) 2002-2010 Red Hat, Inc. Copyright (c) 2002-2010 Red Hat, Inc.
Copyright (c) 2011-2014, PostgreSQL Global Development Group
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. (at your option) any later version.
Author: Patrick Macdonald <patrickm@redhat.com> Original Author: Patrick Macdonald <patrickm@redhat.com>
Version: 9.0.0
Overview:
------------------------------------------------------------------------ ------------------------------------------------------------------------
pg_filedump is a utility to format PostgreSQL heap/index/control files Overview:
pg_filedump is a utility to format PostgreSQL heap/index/control files
into a human-readable form. You can format/dump the files several ways, into a human-readable form. You can format/dump the files several ways,
as listed in the Invocation section, as well as dumping straight binary. as listed in the Invocation section, as well as dumping straight binary.
@ -22,63 +23,42 @@ The type of file (heap/index) can usually be determined automatically
by the content of the blocks within the file. However, to format a by the content of the blocks within the file. However, to format a
pg_control file you must use the -c option. pg_control file you must use the -c option.
The default is to format the entire file using the block size listed on The default is to format the entire file using the block size listed in
block 0 (heap/index files) and display block relative addresses. These block 0 and display block relative addresses. These defaults can be
defaults can be modified using run-time options. modified using run-time options.
Some options may seem strange but they're there for a reason. For Some options may seem strange but they're there for a reason. For
example, block size. It's there because if the header of block 0 is example, block size. It's there because if the header of block 0 is
corrupt, you need a method of forcing a block size. corrupt, you need a method of forcing a block size.
Release Notes / Databases Supported
-----------------------------------------------------------------------
V9.0.0 Must be compiled against a PostgreSQL 9.0 installation.
Supports: PostgreSQL 9.0.x
V8.4.0 Must be compiled against a PostgreSQL 8.4 installation.
Supports: PostgreSQL 8.4.x
V8.3.0 Must be compiled against a PostgreSQL 8.3 installation.
Supports: PostgreSQL 8.3.x
V8.2.0 Must be compiled against a PostgreSQL 8.2 installation.
Supports: PostgreSQL 8.2.x
V8.1.1 Must be compiled against a PostgreSQL 8.1 installation.
Supports: PostgreSQL 8.1.x
V4.0 Must be compiled against a PostgreSQL 8.0 installation.
Supports: PostgreSQL 8.0.x
V3.0 Must be compiled against a PostgreSQL 7.4 installation.
Supports: PostgreSQL 7.4.x
V2.0 Must be compiled against a PostgreSQL 7.3 installation.
Supports: PostgreSQL - Red Hat Edition 3.0,
Red Hat Database 2.x, Red Hat Database 1.x
PostgreSQL 7.3.x, PostgreSQL 7.2.x, PostgreSQL 7.1.x
V1.0 Must be compiled against a PostgreSQL 7.1 or PostgreSQL 7.2
installation.
Supports: Red Hat Database 2.x, Red Hat Database 1.x
PostgreSQL 7.2.x, PostgreSQL 7.1.x
Compile/Installation:
------------------------------------------------------------------------ ------------------------------------------------------------------------
There are two makefiles included in this package. Makefile is a Compile/Installation:
standalone makefile for pg_filedump. Alter the include and src
variables to point to the proper directories. Makefile.contrib can be To compile pg_filedump, you will need to have a properly configured
used if the package was untarred in the contrib directory of a PostgreSQL source tree or complete install tree (with include files)
PostgreSQL build tree. of the appropriate PostgreSQL major version.
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
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 method requires that the pg_config program be in your PATH, but should
not require any manual adjustments of the Makefile.
------------------------------------------------------------------------
Invocation: Invocation:
------------------------------------------------------------------------
pg_filedump [-abcdfhixy] [-R startblock [endblock]] [-S blocksize] file pg_filedump [-abcdfhixy] [-R startblock [endblock]] [-S blocksize] file
Defaults are: relative addressing, range of the entire file, block size Defaults are: relative addressing, range of the entire file, block size
@ -107,3 +87,6 @@ The following options are valid for control files:
-c Interpret the file listed as a control file -c Interpret the file listed as a control file
-f Display formatted content dump along with interpretation -f Display formatted content dump along with interpretation
-S Force block size to [blocksize] -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

@ -1,9 +1,9 @@
/* /*
* pg_filedump.c - PostgreSQL file dump utility for dumping and * pg_filedump.c - PostgreSQL file dump utility for dumping and
* formatting heap (data), index and control files. * formatting heap (data), index and control files.
* Version 9.0.0 for PostgreSQL 9.0
* *
* Copyright (c) 2002-2010 Red Hat, Inc. All rights reserved. * Copyright (c) 2002-2010 Red Hat, Inc.
* Copyright (c) 2011-2014, PostgreSQL Global Development Group
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -19,14 +19,13 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* Author: Patrick Macdonald <patrickm@redhat.com> * Original Author: Patrick Macdonald <patrickm@redhat.com>
*
* Component of: PostgreSQL - Red Hat Edition - Utilities / Tools
*
*/ */
#include "pg_filedump.h" #include "pg_filedump.h"
#include "utils/pg_crc_tables.h"
// Global variables for ease of use mostly // Global variables for ease of use mostly
static FILE *fp = NULL; // File to dump or format static FILE *fp = NULL; // File to dump or format
static char *fileName = NULL; // File name for display static char *fileName = NULL; // File name for display
@ -57,18 +56,21 @@ static void DumpBinaryBlock ();
static void DumpFileContents (); static void DumpFileContents ();
// Send properly formed usage information to the user. // Send properly formed usage information to the user.
static void static void
DisplayOptions (unsigned int validOptions) DisplayOptions (unsigned int validOptions)
{ {
if (validOptions == OPT_RC_COPYRIGHT) if (validOptions == OPT_RC_COPYRIGHT)
printf printf
("\nVersion 9.0.0 (PostgreSQL 9.0) Copyright (c) 2002-2010 Red Hat, Inc.\n"); ("\nVersion %s (for %s)"
"\nCopyright (c) 2002-2010 Red Hat, Inc."
"\nCopyright (c) 2011-2014, PostgreSQL Global Development Group\n",
FD_VERSION, FD_PG_VERSION);
printf printf
("\nUsage: pg_filedump [-abcdfhixy] [-R startblock [endblock]] [-S blocksize] file\n\n" ("\nUsage: pg_filedump [-abcdfhixy] [-R startblock [endblock]] [-S blocksize] file\n\n"
"Display formatted contents of a PostgreSQL heap/index/control file\n" "Display formatted contents of a PostgreSQL heap/index/control file\n"
" Defaults are: relative addressing, range of the entire file, block\n" "Defaults are: relative addressing, range of the entire file, block\n"
" size as listed on block 0 in the file\n\n" " size as listed on block 0 in the file\n\n"
"The following options are valid for heap and index files:\n" "The following options are valid for heap and index files:\n"
" -a Display absolute addresses when formatting (Block header\n" " -a Display absolute addresses when formatting (Block header\n"
@ -91,12 +93,12 @@ DisplayOptions (unsigned int validOptions)
" -c Interpret the file listed as a control file\n" " -c Interpret the file listed as a control file\n"
" -f Display formatted content dump along with interpretation\n" " -f Display formatted content dump along with interpretation\n"
" -S Force block size to [blocksize]\n" " -S Force block size to [blocksize]\n"
"\nReport bugs to <rhdb@sources.redhat.com>\n"); "\nReport bugs to <pgsql-bugs@postgresql.org>\n");
} }
// Iterate through the provided options and set the option flags. // Iterate through the provided options and set the option flags.
// An error will result in a positive rc and will force a display // An error will result in a positive rc and will force a display
// of the usage information. This routine returns enum // of the usage information. This routine returns enum
// optionReturnCode values. // optionReturnCode values.
static unsigned int static unsigned int
ConsumeOptions (int numOptions, char **options) ConsumeOptions (int numOptions, char **options)
@ -170,7 +172,7 @@ ConsumeOptions (int numOptions, char **options)
} }
} }
// Check for the special case where the user forces a block size // Check for the special case where the user forces a block size
// instead of having the tool determine it. This is useful if // instead of having the tool determine it. This is useful if
// the header of block 0 is corrupt and gives a garbage block size // the header of block 0 is corrupt and gives a garbage block size
else if ((optionStringLength == 2) else if ((optionStringLength == 2)
&& (strcmp (optionString, "-S") == 0)) && (strcmp (optionString, "-S") == 0))
@ -220,8 +222,8 @@ ConsumeOptions (int numOptions, char **options)
} }
else else
{ {
// Could be the case where the help flag is used without a // Could be the case where the help flag is used without a
// filename. Otherwise, the last option isn't a file // filename. Otherwise, the last option isn't a file
if (strcmp (optionString, "-h") == 0) if (strcmp (optionString, "-h") == 0)
rc = OPT_RC_COPYRIGHT; rc = OPT_RC_COPYRIGHT;
else else
@ -250,12 +252,12 @@ ConsumeOptions (int numOptions, char **options)
{ {
switch (optionString[y]) switch (optionString[y])
{ {
// Use absolute addressing // Use absolute addressing
case 'a': case 'a':
SET_OPTION (blockOptions, BLOCK_ABSOLUTE, 'a'); SET_OPTION (blockOptions, BLOCK_ABSOLUTE, 'a');
break; break;
// Dump the binary contents of the page // Dump the binary contents of the page
case 'b': case 'b':
SET_OPTION (blockOptions, BLOCK_BINARY, 'b'); SET_OPTION (blockOptions, BLOCK_BINARY, 'b');
break; break;
@ -276,7 +278,7 @@ ConsumeOptions (int numOptions, char **options)
SET_OPTION (blockOptions, BLOCK_FORMAT, 'f'); SET_OPTION (blockOptions, BLOCK_FORMAT, 'f');
break; break;
// Display the usage screen // Display the usage screen
case 'h': case 'h':
rc = OPT_RC_COPYRIGHT; rc = OPT_RC_COPYRIGHT;
break; break;
@ -286,7 +288,7 @@ ConsumeOptions (int numOptions, char **options)
SET_OPTION (itemOptions, ITEM_DETAIL, 'i'); SET_OPTION (itemOptions, ITEM_DETAIL, 'i');
break; break;
// Interpret items as index values // Interpret items as standard index values
case 'x': case 'x':
SET_OPTION (itemOptions, ITEM_INDEX, 'x'); SET_OPTION (itemOptions, ITEM_INDEX, 'x');
if (itemOptions & ITEM_HEAP) if (itemOptions & ITEM_HEAP)
@ -325,7 +327,7 @@ ConsumeOptions (int numOptions, char **options)
// If the user requested a control file dump, a pure binary // If the user requested a control file dump, a pure binary
// block dump or a non-interpreted formatted dump, mask off // block dump or a non-interpreted formatted dump, mask off
// all other block level options (with a few exceptions) // all other block level options (with a few exceptions)
if (rc == OPT_RC_VALID) if (rc == OPT_RC_VALID)
{ {
// The user has requested a control file dump, only -f and // The user has requested a control file dump, only -f and
@ -366,8 +368,8 @@ ConsumeOptions (int numOptions, char **options)
return (rc); return (rc);
} }
// Given the index into the parameter list, convert and return the // Given the index into the parameter list, convert and return the
// current string to a number if possible // current string to a number if possible
static int static int
GetOptionValue (char *optionString) GetOptionValue (char *optionString)
{ {
@ -421,7 +423,7 @@ GetSpecialSectionType (Page page)
unsigned int specialValue; unsigned int specialValue;
PageHeader pageHeader = (PageHeader) page; PageHeader pageHeader = (PageHeader) page;
// If this is not a partial header, check the validity of the // If this is not a partial header, check the validity of the
// special section offset and contents // special section offset and contents
if (bytesToFormat > sizeof (PageHeaderData)) if (bytesToFormat > sizeof (PageHeaderData))
{ {
@ -434,20 +436,29 @@ GetSpecialSectionType (Page page)
rc = SPEC_SECT_ERROR_BOUNDARY; rc = SPEC_SECT_ERROR_BOUNDARY;
else else
{ {
// we may need to examine last 2 bytes of page to identify index
uint16 *ptype = (uint16 *) (buffer + blockSize - sizeof(uint16));
specialSize = blockSize - specialOffset; specialSize = blockSize - specialOffset;
// If there is a special section, use its size to guess its // 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) if (specialSize == 0)
rc = SPEC_SECT_NONE; rc = SPEC_SECT_NONE;
else if (specialSize == MAXALIGN (sizeof (uint32))) 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) if (bytesToFormat == blockSize)
{ {
specialValue = *((int *) (buffer + specialOffset)); specialValue = *((int *) (buffer + specialOffset));
if (specialValue == SEQUENCE_MAGIC) if (specialValue == SEQUENCE_MAGIC)
rc = SPEC_SECT_SEQUENCE; 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))) else if (specialSize == MAXALIGN (sizeof (GinPageOpaqueData)))
rc = SPEC_SECT_INDEX_GIN; rc = SPEC_SECT_INDEX_GIN;
else else
@ -456,6 +467,12 @@ GetSpecialSectionType (Page page)
else else
rc = SPEC_SECT_ERROR_UNKNOWN; 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))) else if (specialSize == MAXALIGN (sizeof (GinPageOpaqueData)))
rc = SPEC_SECT_INDEX_GIN; rc = SPEC_SECT_INDEX_GIN;
else if (specialSize > 2 && bytesToFormat == blockSize) 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 // As of 8.3, BTree, Hash, and GIST all have the same size
// special section, but the last two bytes of the section // special section, but the last two bytes of the section
// can be checked to determine what's what. // 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))) specialSize == MAXALIGN (sizeof (BTPageOpaqueData)))
rc = SPEC_SECT_INDEX_BTREE; rc = SPEC_SECT_INDEX_BTREE;
else if (ptype == HASHO_PAGE_ID && else if (*ptype == HASHO_PAGE_ID &&
specialSize == MAXALIGN (sizeof (HashPageOpaqueData))) specialSize == MAXALIGN (sizeof (HashPageOpaqueData)))
rc = SPEC_SECT_INDEX_HASH; rc = SPEC_SECT_INDEX_HASH;
else if (ptype == GIST_PAGE_ID && else if (*ptype == GIST_PAGE_ID &&
specialSize == MAXALIGN (sizeof (GISTPageOpaqueData))) specialSize == MAXALIGN (sizeof (GISTPageOpaqueData)))
rc = SPEC_SECT_INDEX_GIST; rc = SPEC_SECT_INDEX_GIST;
else else
@ -517,7 +532,7 @@ CreateDumpFileHeader (int numOptions, char **options)
time_t rightNow = time (NULL); time_t rightNow = time (NULL);
// Iterate through the options and cache them. // Iterate through the options and cache them.
// The maximum we can display is 50 option characters + spaces. // The maximum we can display is 50 option characters + spaces.
for (x = 1; x < (numOptions - 1); x++) for (x = 1; x < (numOptions - 1); x++)
{ {
if ((strlen (optionBuffer) + strlen (options[x])) > 50) if ((strlen (optionBuffer) + strlen (options[x])) > 50)
@ -528,12 +543,13 @@ CreateDumpFileHeader (int numOptions, char **options)
printf printf
("\n*******************************************************************\n" ("\n*******************************************************************\n"
"* PostgreSQL File/Block Formatted Dump Utility - Version 9.0.0\n*\n" "* PostgreSQL File/Block Formatted Dump Utility - Version %s\n"
"*\n"
"* File: %s\n" "* File: %s\n"
"* Options used: %s\n*\n" "* Options used: %s\n*\n"
"* Dump created on: %s" "* Dump created on: %s"
"*******************************************************************\n", "*******************************************************************\n",
fileName, (strlen (optionBuffer)) ? optionBuffer : "None", FD_VERSION, fileName, (strlen (optionBuffer)) ? optionBuffer : "None",
ctime (&rightNow)); ctime (&rightNow));
} }
@ -582,6 +598,8 @@ FormatHeader (Page page)
strcat (flagString, "HAS_FREE_LINES|"); strcat (flagString, "HAS_FREE_LINES|");
if (pageHeader->pd_flags & PD_PAGE_FULL) if (pageHeader->pd_flags & PD_PAGE_FULL)
strcat (flagString, "PAGE_FULL|"); strcat (flagString, "PAGE_FULL|");
if (pageHeader->pd_flags & PD_ALL_VISIBLE)
strcat (flagString, "ALL_VISIBLE|");
if (strlen (flagString)) if (strlen (flagString))
flagString[strlen (flagString) - 1] = '\0'; flagString[strlen (flagString) - 1] = '\0';
@ -591,15 +609,15 @@ FormatHeader (Page page)
" Block: Size %4d Version %4u Upper %4u (0x%04hx)\n" " Block: Size %4d Version %4u Upper %4u (0x%04hx)\n"
" LSN: logid %6d recoff 0x%08x Special %4u (0x%04hx)\n" " LSN: logid %6d recoff 0x%08x Special %4u (0x%04hx)\n"
" Items: %4d Free Space: %4u\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", " Length (including item array): %u\n\n",
pageOffset, pageHeader->pd_lower, pageHeader->pd_lower, pageOffset, pageHeader->pd_lower, pageHeader->pd_lower,
(int) PageGetPageSize (page), blockVersion, (int) PageGetPageSize (page), blockVersion,
pageHeader->pd_upper, pageHeader->pd_upper, pageHeader->pd_upper, pageHeader->pd_upper,
pageLSN.xlogid, pageLSN.xrecoff, (uint32) (pageLSN >> 32), (uint32) pageLSN,
pageHeader->pd_special, pageHeader->pd_special, pageHeader->pd_special, pageHeader->pd_special,
maxOffset, pageHeader->pd_upper - pageHeader->pd_lower, 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, pageHeader->pd_flags, flagString,
headerBytes); headerBytes);
@ -638,7 +656,7 @@ FormatHeader (Page page)
(" Error: End of block encountered within the header." (" Error: End of block encountered within the header."
" Bytes read: %4u.\n\n", bytesToFormat); " Bytes read: %4u.\n\n", bytesToFormat);
// A request to dump the formatted binary of the block (header, // A request to dump the formatted binary of the block (header,
// items and special section). It's best to dump even on an error // items and special section). It's best to dump even on an error
// so the user can see the raw image. // so the user can see the raw image.
if (blockOptions & BLOCK_FORMAT) if (blockOptions & BLOCK_FORMAT)
@ -647,7 +665,7 @@ FormatHeader (Page page)
return (rc); return (rc);
} }
// Dump out formatted items that reside on this block // Dump out formatted items that reside on this block
static void static void
FormatItemBlock (Page page) FormatItemBlock (Page page)
{ {
@ -666,8 +684,8 @@ FormatItemBlock (Page page)
printf ("<Data> ------ \n"); printf ("<Data> ------ \n");
// Loop through the items on the block. Check if the block is // Loop through the items on the block. Check if the block is
// empty and has a sensible item array listed before running // empty and has a sensible item array listed before running
// through each item // through each item
if (maxOffset == 0) if (maxOffset == 0)
printf (" Empty block - no items listed \n\n"); printf (" Empty block - no items listed \n\n");
else if ((maxOffset < 0) || (maxOffset > blockSize)) else if ((maxOffset < 0) || (maxOffset > blockSize))
@ -678,16 +696,36 @@ FormatItemBlock (Page page)
int formatAs; int formatAs;
char textFlags[16]; char textFlags[16];
// First, honour requests to format items a special way, then // First, honour requests to format items a special way, then
// use the special section to determine the format style // use the special section to determine the format style
if (itemOptions & ITEM_INDEX) if (itemOptions & ITEM_INDEX)
formatAs = ITEM_INDEX; formatAs = ITEM_INDEX;
else if (itemOptions & ITEM_HEAP) else if (itemOptions & ITEM_HEAP)
formatAs = ITEM_HEAP; formatAs = ITEM_HEAP;
else if (specialType != SPEC_SECT_NONE)
formatAs = ITEM_INDEX;
else else
formatAs = ITEM_HEAP; 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++) for (x = 1; x < (maxOffset + 1); x++)
{ {
@ -730,11 +768,11 @@ FormatItemBlock (Page page)
else else
{ {
// If the user requests that the items be interpreted as // If the user requests that the items be interpreted as
// heap or index items... // heap or index items...
if (itemOptions & ITEM_DETAIL) if (itemOptions & ITEM_DETAIL)
FormatItem (itemSize, itemOffset, formatAs); FormatItem (itemSize, itemOffset, formatAs);
// Dump the items contents in hex and ascii // Dump the items contents in hex and ascii
if (blockOptions & BLOCK_FORMAT) if (blockOptions & BLOCK_FORMAT)
FormatBinary (itemSize, itemOffset); FormatBinary (itemSize, itemOffset);
@ -751,9 +789,16 @@ static void
FormatItem (unsigned int numBytes, unsigned int startIndex, FormatItem (unsigned int numBytes, unsigned int startIndex,
unsigned int formatAs) 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) if (formatAs == ITEM_INDEX)
{ {
// It is an IndexTuple item, so dump the index header
if (numBytes < SizeOfIptrData) if (numBytes < SizeOfIptrData)
{ {
if (numBytes) if (numBytes)
@ -766,17 +811,96 @@ FormatItem (unsigned int numBytes, unsigned int startIndex,
" Has Nulls: %u Has Varwidths: %u\n\n", " Has Nulls: %u Has Varwidths: %u\n\n",
((uint32) ((itup->t_tid.ip_blkid.bi_hi << 16) | ((uint32) ((itup->t_tid.ip_blkid.bi_hi << 16) |
(uint16) itup->t_tid.ip_blkid.bi_lo)), (uint16) itup->t_tid.ip_blkid.bi_lo)),
itup->t_tid.ip_posid, (int) IndexTupleSize (itup), itup->t_tid.ip_posid,
IndexTupleHasNulls (itup), IndexTupleHasVarwidths (itup)); (int) IndexTupleSize(itup),
IndexTupleHasNulls(itup) ? 1 : 0,
IndexTupleHasVarwidths(itup) ? 1 : 0);
if (numBytes != IndexTupleSize (itup)) if (numBytes != IndexTupleSize (itup))
printf (" Error: Item size difference. Given <%u>, " printf (" Error: Item size difference. Given <%u>, "
"Internal <%d>.\n", numBytes, (int) IndexTupleSize (itup)); "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
{
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 else
{ {
// It is a heap item, so dump the heap header // It is a HeapTuple item, so dump the heap header
int alignedSize = MAXALIGN (sizeof (HeapTupleHeaderData)); int alignedSize = MAXALIGN (sizeof (HeapTupleHeaderData));
if (numBytes < alignedSize) if (numBytes < alignedSize)
@ -809,7 +933,7 @@ FormatItem (unsigned int numBytes, unsigned int startIndex,
printf (" XMIN: %u XMAX: %u CID|XVAC: %u", printf (" XMIN: %u XMAX: %u CID|XVAC: %u",
HeapTupleHeaderGetXmin(htup), HeapTupleHeaderGetXmin(htup),
HeapTupleHeaderGetXmax(htup), HeapTupleHeaderGetRawXmax(htup),
HeapTupleHeaderGetRawCommandId(htup)); HeapTupleHeaderGetRawCommandId(htup));
if (infoMask & HEAP_HASOID) if (infoMask & HEAP_HASOID)
@ -823,7 +947,7 @@ FormatItem (unsigned int numBytes, unsigned int startIndex,
t_ctid.ip_blkid.bi_lo)), htup->t_ctid.ip_posid, t_ctid.ip_blkid.bi_lo)), htup->t_ctid.ip_posid,
localNatts, htup->t_hoff); localNatts, htup->t_hoff);
// Place readable versions of the tuple info mask into a buffer. // Place readable versions of the tuple info mask into a buffer.
// Assume that the string can not expand beyond 256. // Assume that the string can not expand beyond 256.
flagString[0] = '\0'; flagString[0] = '\0';
if (infoMask & HEAP_HASNULL) if (infoMask & HEAP_HASNULL)
@ -834,12 +958,14 @@ FormatItem (unsigned int numBytes, unsigned int startIndex,
strcat (flagString, "HASEXTERNAL|"); strcat (flagString, "HASEXTERNAL|");
if (infoMask & HEAP_HASOID) if (infoMask & HEAP_HASOID)
strcat (flagString, "HASOID|"); strcat (flagString, "HASOID|");
if (infoMask & HEAP_XMAX_KEYSHR_LOCK)
strcat (flagString, "XMAX_KEYSHR_LOCK|");
if (infoMask & HEAP_COMBOCID) if (infoMask & HEAP_COMBOCID)
strcat (flagString, "COMBOCID|"); strcat (flagString, "COMBOCID|");
if (infoMask & HEAP_XMAX_EXCL_LOCK) if (infoMask & HEAP_XMAX_EXCL_LOCK)
strcat (flagString, "XMAX_EXCL_LOCK|"); strcat (flagString, "XMAX_EXCL_LOCK|");
if (infoMask & HEAP_XMAX_SHARED_LOCK) if (infoMask & HEAP_XMAX_LOCK_ONLY)
strcat (flagString, "XMAX_SHARED_LOCK|"); strcat (flagString, "XMAX_LOCK_ONLY|");
if (infoMask & HEAP_XMIN_COMMITTED) if (infoMask & HEAP_XMIN_COMMITTED)
strcat (flagString, "XMIN_COMMITTED|"); strcat (flagString, "XMIN_COMMITTED|");
if (infoMask & HEAP_XMIN_INVALID) if (infoMask & HEAP_XMIN_INVALID)
@ -857,6 +983,8 @@ FormatItem (unsigned int numBytes, unsigned int startIndex,
if (infoMask & HEAP_MOVED_IN) if (infoMask & HEAP_MOVED_IN)
strcat (flagString, "MOVED_IN|"); strcat (flagString, "MOVED_IN|");
if (infoMask2 & HEAP_KEYS_UPDATED)
strcat (flagString, "KEYS_UPDATED|");
if (infoMask2 & HEAP_HOT_UPDATED) if (infoMask2 & HEAP_HOT_UPDATED)
strcat (flagString, "HOT_UPDATED|"); strcat (flagString, "HOT_UPDATED|");
if (infoMask2 & HEAP_ONLY_TUPLE) if (infoMask2 & HEAP_ONLY_TUPLE)
@ -868,7 +996,7 @@ FormatItem (unsigned int numBytes, unsigned int startIndex,
printf (" infomask: 0x%04x (%s) \n", infoMask, flagString); printf (" infomask: 0x%04x (%s) \n", infoMask, flagString);
// As t_bits is a variable length array, determine the length of // As t_bits is a variable length array, determine the length of
// the header proper // the header proper
if (infoMask & HEAP_HASNULL) if (infoMask & HEAP_HASNULL)
bitmapLength = BITMAPLEN (localNatts); bitmapLength = BITMAPLEN (localNatts);
else else
@ -903,9 +1031,8 @@ FormatItem (unsigned int numBytes, unsigned int startIndex,
} }
// On blocks that have special sections, we have to interpret the // On blocks that have special sections, print the contents
// contents based on size of the special section (since there is // according to previously determined special section type
// no other way)
static void static void
FormatSpecial () FormatSpecial ()
{ {
@ -928,7 +1055,7 @@ FormatSpecial ()
printf (" Sequence: 0x%08x\n", SEQUENCE_MAGIC); printf (" Sequence: 0x%08x\n", SEQUENCE_MAGIC);
break; break;
// Btree index section // Btree index section
case SPEC_SECT_INDEX_BTREE: case SPEC_SECT_INDEX_BTREE:
{ {
BTPageOpaque btreeSection = (BTPageOpaque) (buffer + specialOffset); BTPageOpaque btreeSection = (BTPageOpaque) (buffer + specialOffset);
@ -961,7 +1088,7 @@ FormatSpecial ()
} }
break; break;
// Hash index section // Hash index section
case SPEC_SECT_INDEX_HASH: case SPEC_SECT_INDEX_HASH:
{ {
HashPageOpaque hashSection = (HashPageOpaque) (buffer + specialOffset); HashPageOpaque hashSection = (HashPageOpaque) (buffer + specialOffset);
@ -997,6 +1124,8 @@ FormatSpecial ()
strcat (flagString, "DELETED|"); strcat (flagString, "DELETED|");
if (gistSection->flags & F_TUPLES_DELETED) if (gistSection->flags & F_TUPLES_DELETED)
strcat (flagString, "TUPLES_DELETED|"); strcat (flagString, "TUPLES_DELETED|");
if (gistSection->flags & F_FOLLOW_RIGHT)
strcat (flagString, "FOLLOW_RIGHT|");
if (strlen (flagString)) if (strlen (flagString))
flagString[strlen (flagString) - 1] = '\0'; flagString[strlen (flagString) - 1] = '\0';
printf (" GIST Index Section:\n" printf (" GIST Index Section:\n"
@ -1019,6 +1148,12 @@ FormatSpecial ()
strcat (flagString, "LEAF|"); strcat (flagString, "LEAF|");
if (ginSection->flags & GIN_DELETED) if (ginSection->flags & GIN_DELETED)
strcat (flagString, "DELETED|"); strcat (flagString, "DELETED|");
if (ginSection->flags & GIN_META)
strcat (flagString, "META|");
if (ginSection->flags & GIN_LIST)
strcat (flagString, "LIST|");
if (ginSection->flags & GIN_LIST_FULLROW)
strcat (flagString, "FULLROW|");
if (strlen (flagString)) if (strlen (flagString))
flagString[strlen (flagString) - 1] = '\0'; flagString[strlen (flagString) - 1] = '\0';
printf (" GIN Index Section:\n" printf (" GIN Index Section:\n"
@ -1030,13 +1165,37 @@ FormatSpecial ()
} }
break; 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 // No idea what type of special section this is
default: default:
printf (" Unknown special section type. Type: <%u>.\n", specialType); printf (" Unknown special section type. Type: <%u>.\n", specialType);
break; break;
} }
// Dump the formatted contents of the special section // Dump the formatted contents of the special section
if (blockOptions & BLOCK_FORMAT) if (blockOptions & BLOCK_FORMAT)
{ {
if (specialType == SPEC_SECT_ERROR_BOUNDARY) if (specialType == SPEC_SECT_ERROR_BOUNDARY)
@ -1061,17 +1220,17 @@ FormatBlock ()
blockSize) ? "***************" : " PARTIAL BLOCK "); blockSize) ? "***************" : " PARTIAL BLOCK ");
// Either dump out the entire block in hex+acsii fashion or // Either dump out the entire block in hex+acsii fashion or
// interpret the data based on block structure // interpret the data based on block structure
if (blockOptions & BLOCK_NO_INTR) if (blockOptions & BLOCK_NO_INTR)
FormatBinary (bytesToFormat, 0); FormatBinary (bytesToFormat, 0);
else else
{ {
int rc; int rc;
// Every block contains a header, items and possibly a special // Every block contains a header, items and possibly a special
// section. Beware of partial block reads though // section. Beware of partial block reads though
rc = FormatHeader (page); rc = FormatHeader (page);
// If we didn't encounter a partial read in the header, carry on... // If we didn't encounter a partial read in the header, carry on...
if (rc != EOF_ENCOUNTERED) if (rc != EOF_ENCOUNTERED)
{ {
FormatItemBlock (page); FormatItemBlock (page);
@ -1088,11 +1247,13 @@ FormatControl ()
{ {
unsigned int localPgVersion = 0; unsigned int localPgVersion = 0;
unsigned int controlFileSize = 0; unsigned int controlFileSize = 0;
time_t cd_time;
time_t cp_time;
printf printf
("\n<pg_control Contents> *********************************************\n\n"); ("\n<pg_control Contents> *********************************************\n\n");
// Check the version // Check the version
if (bytesToFormat >= offsetof (ControlFileData, catalog_version_no)) if (bytesToFormat >= offsetof (ControlFileData, catalog_version_no))
localPgVersion = ((ControlFileData *) buffer)->pg_control_version; localPgVersion = ((ControlFileData *) buffer)->pg_control_version;
@ -1144,6 +1305,10 @@ FormatControl ()
break; break;
} }
/* convert timestamps to system's time_t width */
cd_time = controlData->time;
cp_time = checkPoint->time;
printf (" CRC: %s\n" printf (" CRC: %s\n"
" pg_control Version: %u%s\n" " pg_control Version: %u%s\n"
" Catalog Version: %u\n" " Catalog Version: %u\n"
@ -1178,16 +1343,16 @@ FormatControl ()
controlData->catalog_version_no, controlData->catalog_version_no,
controlData->system_identifier, controlData->system_identifier,
dbState, dbState,
ctime (&(controlData->time)), ctime (&(cd_time)),
controlData->checkPoint.xlogid, controlData->checkPoint.xrecoff, (uint32) (controlData->checkPoint >> 32), (uint32) controlData->checkPoint,
controlData->prevCheckPoint.xlogid, controlData->prevCheckPoint.xrecoff, (uint32) (controlData->prevCheckPoint >> 32), (uint32) controlData->prevCheckPoint,
checkPoint->redo.xlogid, checkPoint->redo.xrecoff, (uint32) (checkPoint->redo >> 32), (uint32) checkPoint->redo,
checkPoint->ThisTimeLineID, checkPoint->ThisTimeLineID,
checkPoint->nextXidEpoch, checkPoint->nextXid, checkPoint->nextXidEpoch, checkPoint->nextXid,
checkPoint->nextOid, checkPoint->nextOid,
checkPoint->nextMulti, checkPoint->nextMultiOffset, checkPoint->nextMulti, checkPoint->nextMultiOffset,
ctime (&checkPoint->time), ctime (&cp_time),
controlData->minRecoveryPoint.xlogid, controlData->minRecoveryPoint.xrecoff, (uint32) (controlData->minRecoveryPoint >> 32), (uint32) controlData->minRecoveryPoint,
controlData->maxAlign, controlData->maxAlign,
controlData->floatFormat, controlData->floatFormat,
(controlData->floatFormat == FLOATFORMAT_VALUE ? (controlData->floatFormat == FLOATFORMAT_VALUE ?
@ -1208,12 +1373,12 @@ FormatControl ()
" Size: Correct <%u> Received <%u>.\n\n", " Size: Correct <%u> Received <%u>.\n\n",
controlFileSize, bytesToFormat); controlFileSize, bytesToFormat);
// If we have an error, force a formatted dump so we can see // If we have an error, force a formatted dump so we can see
// where things are going wrong // where things are going wrong
controlOptions |= CONTROL_FORMAT; controlOptions |= CONTROL_FORMAT;
} }
// Dump hex and ascii representation of data // Dump hex and ascii representation of data
if (controlOptions & CONTROL_FORMAT) if (controlOptions & CONTROL_FORMAT)
{ {
printf ("<pg_control Formatted Dump> *****************" printf ("<pg_control Formatted Dump> *****************"
@ -1222,7 +1387,7 @@ FormatControl ()
} }
} }
// Dump out the contents of the block in hex and ascii. // Dump out the contents of the block in hex and ascii.
// BYTES_PER_LINE bytes are formatted in each line. // BYTES_PER_LINE bytes are formatted in each line.
static void static void
FormatBinary (unsigned int numBytes, unsigned int startIndex) FormatBinary (unsigned int numBytes, unsigned int startIndex)
@ -1235,7 +1400,7 @@ FormatBinary (unsigned int numBytes, unsigned int startIndex)
if (numBytes) if (numBytes)
{ {
// Iterate through a printable row detailing the current // Iterate through a printable row detailing the current
// address, the hex and ascii values // address, the hex and ascii values
for (index = startIndex; index < lastByte; index += BYTES_PER_LINE) for (index = startIndex; index < lastByte; index += BYTES_PER_LINE)
{ {
stopIndex = index + BYTES_PER_LINE; stopIndex = index + BYTES_PER_LINE;
@ -1312,7 +1477,7 @@ DumpFileContents ()
if (bytesToFormat == 0) if (bytesToFormat == 0)
{ {
// fseek() won't pop an error if you seek passed eof. The next // fseek() won't pop an error if you seek passed eof. The next
// subsequent read gets the error. // subsequent read gets the error.
if (initialRead) if (initialRead)
printf ("Error: Premature end of file encountered.\n"); printf ("Error: Premature end of file encountered.\n");
else if (!(blockOptions & BLOCK_BINARY)) else if (!(blockOptions & BLOCK_BINARY))
@ -1359,7 +1524,7 @@ DumpFileContents ()
int int
main (int argv, char **argc) main (int argv, char **argc)
{ {
// If there is a parameter list, validate the options // If there is a parameter list, validate the options
unsigned int validOptions; unsigned int validOptions;
validOptions = (argv < 2) ? OPT_RC_COPYRIGHT : ConsumeOptions (argv, argc); validOptions = (argv < 2) ? OPT_RC_COPYRIGHT : ConsumeOptions (argv, argc);
@ -1369,12 +1534,12 @@ main (int argv, char **argc)
DisplayOptions (validOptions); DisplayOptions (validOptions);
else else
{ {
// Don't dump the header if we're dumping binary pages // Don't dump the header if we're dumping binary pages
if (!(blockOptions & BLOCK_BINARY)) if (!(blockOptions & BLOCK_BINARY))
CreateDumpFileHeader (argv, argc); CreateDumpFileHeader (argv, argc);
// If the user has not forced a block size, use the size of the // If the user has not forced a block size, use the size of the
// control file data or the information from the block 0 header // control file data or the information from the block 0 header
if (controlOptions) if (controlOptions)
{ {
if (!(controlOptions & CONTROL_FORCED)) if (!(controlOptions & CONTROL_FORCED))

View File

@ -1,9 +1,9 @@
/* /*
* pg_filedump.h - PostgreSQL file dump utility for dumping and * pg_filedump.h - PostgreSQL file dump utility for dumping and
* formatting heap (data), index and control files. * formatting heap (data), index and control files.
* Version 9.0.0 for PostgreSQL 9.0 *
* * Copyright (c) 2002-2010 Red Hat, Inc.
* Copyright (c) 2002-2010 Red Hat, Inc. All rights reserved. * Copyright (c) 2011-2014, PostgreSQL Global Development Group
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -19,25 +19,27 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* Author: Patrick Macdonald <patrickm@redhat.com> * Original Author: Patrick Macdonald <patrickm@redhat.com>
*
* Component of: PostgreSQL - Red Hat Edition - Utilities / Tools
*
*/ */
#include <stdio.h> #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 <time.h>
#include <ctype.h> #include <ctype.h>
#include "postgres.h" #include "access/gin_private.h"
#include "storage/bufpage.h"
#include "access/hash.h"
#include "access/gin.h"
#include "access/gist.h" #include "access/gist.h"
#include "access/nbtree.h" #include "access/hash.h"
#include "access/itup.h"
#include "access/htup.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 "catalog/pg_control.h"
#include "storage/bufpage.h"
// Options for Block formatting operations // Options for Block formatting operations
static unsigned int blockOptions = 0; static unsigned int blockOptions = 0;
@ -52,16 +54,18 @@ typedef enum
} }
blockSwitches; blockSwitches;
static int blockStart = -1; // -R [start]: Block range start static int blockStart = -1; // -R [start]: Block range start
static int blockEnd = -1; // -R [end]: Block range end static int blockEnd = -1; // -R [end]: Block range end
// Options for Item formatting operations // Options for Item formatting operations
static unsigned int itemOptions = 0; static unsigned int itemOptions = 0;
typedef enum typedef enum
{ {
ITEM_DETAIL = 0x00000001, // -i: Display interpreted items ITEM_DETAIL = 0x00000001, // -i: Display interpreted items
ITEM_HEAP = 0x00000002, // -y: Blocks contain heap items ITEM_HEAP = 0x00000002, // -y: Blocks contain HeapTuple items
ITEM_INDEX = 0x00000004 // -x: Blocks contain index 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; itemSwitches;
@ -79,12 +83,13 @@ controlSwitches;
typedef enum typedef enum
{ {
SPEC_SECT_NONE, // No special section on block SPEC_SECT_NONE, // No special section on block
SPEC_SECT_SEQUENCE, // Sequence info in special section SPEC_SECT_SEQUENCE, // Sequence info in special section
SPEC_SECT_INDEX_BTREE, // BTree index info in special section SPEC_SECT_INDEX_BTREE, // BTree index info in special section
SPEC_SECT_INDEX_HASH, // Hash index info in special section SPEC_SECT_INDEX_HASH, // Hash index info in special section
SPEC_SECT_INDEX_GIST, // GIST 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_GIN, // GIN index info in special section
SPEC_SECT_ERROR_UNKNOWN, // Unknown error SPEC_SECT_INDEX_SPGIST, // SP-GIST index info in special section
SPEC_SECT_ERROR_UNKNOWN, // Unknown error
SPEC_SECT_ERROR_BOUNDARY // Boundary error SPEC_SECT_ERROR_BOUNDARY // Boundary error
} }
specialSectionTypes; specialSectionTypes;
@ -104,7 +109,7 @@ typedef enum
optionReturnCodes; optionReturnCodes;
// Simple macro to check for duplicate options and then set // Simple macro to check for duplicate options and then set
// an option flag for later consumption // an option flag for later consumption
#define SET_OPTION(_x,_y,_z) if (_x & _y) \ #define SET_OPTION(_x,_y,_z) if (_x & _y) \
{ \ { \
rc = OPT_RC_DUPLICATE; \ rc = OPT_RC_DUPLICATE; \