Commit d8240a18 authored by Michael Meskes's avatar Michael Meskes

Imported Upstream version 8.2

parent 08c10021
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
......
pg_filedump - Display formatted contents of a PostgreSQL heap/index/control
file.
Copyright (c) 2002, 2003, 2005 Red Hat, Inc.
Copyright (c) 2002-2007 Red Hat, Inc.
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
......@@ -10,7 +10,7 @@ the Free Software Foundation; either version 2 of the License, or
Author: Patrick Macdonald <patrickm@redhat.com>
Version: 8.1.1
Version: 8.2.0
Overview:
------------------------------------------------------------------------
......@@ -33,6 +33,9 @@ corrupt, you need a method of forcing a block size.
Release Notes / Databases Supported
-----------------------------------------------------------------------
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
......
/*
* pg_filedump.c - PostgreSQL file dump utility for dumping and
* formatting heap(data), index and control files.
* Version 8.1.1 for PostgreSQL 8.1
* Version 8.2.0 for PostgreSQL 8.2
*
* Copyright (c) 2002, 2003, 2005 Red Hat, Inc. All rights reserved.
* Copyright (c) 2002-2007 Red Hat, Inc. All rights reserved.
*
* 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
......@@ -44,6 +44,7 @@ static int GetOptionValue (char *optionString);
static void FormatBlock ();
static unsigned int GetBlockSize ();
static unsigned int GetSpecialSectionType (Page page);
static bool IsBtreeMetaPage(Page page);
static void CreateDumpFileHeader (int numOptions, char **options);
static int FormatHeader (Page page);
static void FormatItemBlock (Page page);
......@@ -62,7 +63,7 @@ DisplayOptions (unsigned int validOptions)
{
if (validOptions == OPT_RC_COPYRIGHT)
printf
("\nVersion 8.1.1 (PostgreSQL 8.1) Copyright (c) 2002, 2003, 2005 Red Hat, Inc.\n");
("\nVersion 8.2.0 (PostgreSQL 8.2) Copyright (c) 2002-2007 Red Hat, Inc.\n");
printf
("\nUsage: pg_filedump [-abcdfhixy] [-R startblock [endblock]] [-S blocksize] file\n\n"
......@@ -441,19 +442,32 @@ GetSpecialSectionType (Page page)
rc = SPEC_SECT_NONE;
else if (specialSize == MAXALIGN (sizeof (uint32)))
{
// If MAXALIGN is 8, this could be either a sequence or GIN
if (bytesToFormat == blockSize)
{
specialValue = *((int *) (buffer + specialOffset));
if (specialValue == SEQUENCE_MAGIC)
rc = SPEC_SECT_SEQUENCE;
else if (specialSize == MAXALIGN (sizeof (GinPageOpaqueData)))
rc = SPEC_SECT_INDEX_GIN;
else
rc = SPEC_SECT_INDEX_RTREE;
rc = SPEC_SECT_ERROR_UNKNOWN;
}
else
rc = SPEC_SECT_ERROR_UNKNOWN;
}
else if (specialSize == MAXALIGN (sizeof (GinPageOpaqueData)))
rc = SPEC_SECT_INDEX_GIN;
else if (specialSize == MAXALIGN (sizeof (HashPageOpaqueData)))
{
// As of 7.4, BTree and Hash pages have the same size special
// section. Check for HASHO_FILL to detect if it's hash.
// As of 8.2, it could be GIST, too ... but there seems no
// good way to tell GIST from BTree :-( Also, HASHO_FILL is
// not reliable anymore, it could match cycleid by chance.
// Need to try to get some upstream changes to make this better.
HashPageOpaque hpo = (HashPageOpaque) (buffer + specialOffset);
if (hpo->hasho_filler == HASHO_FILL)
rc = SPEC_SECT_INDEX_HASH;
......@@ -470,6 +484,27 @@ GetSpecialSectionType (Page page)
return (rc);
}
// Check whether page is a btree meta page
static bool
IsBtreeMetaPage(Page page)
{
PageHeader pageHeader = (PageHeader) page;
if ((PageGetSpecialSize (page) == (MAXALIGN (sizeof (BTPageOpaqueData))))
&& (bytesToFormat == blockSize))
{
// As of 7.4, BTree and Hash pages have the same size special
// section. Check for HASHO_FILL to detect if it's hash.
BTPageOpaque btpo =
(BTPageOpaque) ((char *) page + pageHeader->pd_special);
if ((((HashPageOpaque) (btpo))->hasho_filler != HASHO_FILL) &&
(btpo->btpo_flags & BTP_META))
return true;
}
return false;
}
// Display a header for the dump so we know the file name, the options
// used and the time the dump was taken
static void
......@@ -491,7 +526,7 @@ CreateDumpFileHeader (int numOptions, char **options)
printf
("\n*******************************************************************\n"
"* PostgreSQL File/Block Formatted Dump Utility - Version 8.1.1\n*\n"
"* PostgreSQL File/Block Formatted Dump Utility - Version 8.2.0\n*\n"
"* File: %s\n"
"* Options used: %s\n*\n"
"* Dump created on: %s"
......@@ -512,7 +547,7 @@ FormatHeader (Page page)
// Only attempt to format the header if the entire header (minus the item
// array) is available
if (bytesToFormat < sizeof (PageHeaderData))
if (bytesToFormat < offsetof (PageHeaderData, pd_linp[0]))
{
headerBytes = bytesToFormat;
rc = EOF_ENCOUNTERED;
......@@ -521,21 +556,21 @@ FormatHeader (Page page)
{
XLogRecPtr pageLSN = PageGetLSN (page);
int maxOffset = PageGetMaxOffsetNumber (page);
headerBytes = sizeof (PageHeaderData);
headerBytes = offsetof (PageHeaderData, pd_linp[0]);
blockVersion = (unsigned int) PageGetPageLayoutVersion (page);
// The full header exists but we have to check that the item array
// is available or how far we can index into it
if (maxOffset > 0)
{
unsigned int itemLength = maxOffset * sizeof (ItemIdData);
if (bytesToFormat < (headerBytes + itemLength))
unsigned int itemsLength = maxOffset * sizeof (ItemIdData);
if (bytesToFormat < (headerBytes + itemsLength))
{
headerBytes = bytesToFormat;
rc = EOF_ENCOUNTERED;
}
else
headerBytes += itemLength;
headerBytes += itemsLength;
}
// Interpret the content of the header
......@@ -546,35 +581,23 @@ FormatHeader (Page page)
" Items: %4d Free Space: %4u\n"
" Length (including item array): %u\n\n",
pageOffset, pageHeader->pd_lower, pageHeader->pd_lower,
PageGetPageSize (page), blockVersion, pageHeader->pd_upper,
(int) PageGetPageSize (page), blockVersion, pageHeader->pd_upper,
pageHeader->pd_upper,
pageLSN.xlogid, pageLSN.xrecoff, pageHeader->pd_special,
pageHeader->pd_special, maxOffset,
pageHeader->pd_upper - pageHeader->pd_lower, headerBytes);
// Check for the case where this is a BTree page. The meta data stored
// in the header is not recorded in the item array.
if ((PageGetSpecialSize (page) ==
(MAXALIGN (sizeof (BTPageOpaqueData))))
&& (bytesToFormat == blockSize))
// If it's a btree meta page, print the contents of the meta block.
if (IsBtreeMetaPage(page))
{
// As of 7.4, BTree and Hash pages have the same size special
// section. Only look at the meta data if it's a BTree...
BTPageOpaque btpo =
(BTPageOpaque) ((char *) page + pageHeader->pd_special);
if ((((HashPageOpaque) (btpo))->hasho_filler != HASHO_FILL) &&
(btpo->btpo_flags & BTP_META))
{
BTMetaPageData *btpMeta = BTPageGetMeta (buffer);
printf (" BTree Meta Data: Magic (0x%08x) Version (%u)\n"
" Root: Block (%u) Level (%u)\n"
" FastRoot: Block (%u) Level (%u)\n\n",
btpMeta->btm_magic, btpMeta->btm_version,
btpMeta->btm_root, btpMeta->btm_level,
btpMeta->btm_fastroot, btpMeta->btm_fastlevel);
headerBytes += (sizeof (BTMetaPageData) - sizeof (ItemIdData));
}
BTMetaPageData *btpMeta = BTPageGetMeta (buffer);
printf (" BTree Meta Data: Magic (0x%08x) Version (%u)\n"
" Root: Block (%u) Level (%u)\n"
" FastRoot: Block (%u) Level (%u)\n\n",
btpMeta->btm_magic, btpMeta->btm_version,
btpMeta->btm_root, btpMeta->btm_level,
btpMeta->btm_fastroot, btpMeta->btm_fastlevel);
headerBytes += sizeof (BTMetaPageData);
}
// Eye the contents of the header and alert the user to possible
......@@ -619,6 +642,11 @@ FormatItemBlock (Page page)
ItemId itemId;
int maxOffset = PageGetMaxOffsetNumber (page);
// If it's a btree meta page, the meta block is where items would normally
// be; don't print garbage.
if (IsBtreeMetaPage(page))
return;
printf ("<Data> ------ \n");
// Loop through the items on the block. Check if the block is
......@@ -707,12 +735,12 @@ FormatItem (unsigned int numBytes, unsigned int startIndex,
" Has Nulls: %u Has Varwidths: %u\n\n",
((uint32) ((itup->t_tid.ip_blkid.bi_hi << 16) |
(uint16) itup->t_tid.ip_blkid.bi_lo)),
itup->t_tid.ip_posid, IndexTupleSize (itup),
itup->t_tid.ip_posid, (int) IndexTupleSize (itup),
IndexTupleHasNulls (itup), IndexTupleHasVarwidths (itup));
if (numBytes != IndexTupleSize (itup))
printf (" Error: Item size difference. Given <%u>, "
"Internal <%d>.\n", numBytes, IndexTupleSize (itup));
"Internal <%d>.\n", numBytes, (int) IndexTupleSize (itup));
}
}
else
......@@ -844,7 +872,7 @@ static void
FormatSpecial ()
{
PageHeader pageHeader = (PageHeader) buffer;
char flagString[50] = "\0";
char flagString[100] = "\0";
unsigned int specialOffset = pageHeader->pd_special;
unsigned int specialSize =
(blockSize >= specialOffset) ? (blockSize - specialOffset) : 0;
......@@ -862,17 +890,6 @@ FormatSpecial ()
printf (" Sequence: 0x%08x\n", SEQUENCE_MAGIC);
break;
// GIST/RTree index section
case SPEC_SECT_INDEX_RTREE:
{
unsigned int specialValue =
*((unsigned int *) (buffer + specialOffset));
printf (" RTree/GIST Index Section:\n" " Flags: 0x%08x (%s)\n\n",
specialValue,
(specialValue & F_LEAF) ? "LEAF" : "UNKNOWN FLAGS");
}
break;
// Btree index section
case SPEC_SECT_INDEX_BTREE:
{
......@@ -887,25 +904,29 @@ FormatSpecial ()
strcat (flagString, "META|");
if (btreeSection->btpo_flags & BTP_HALF_DEAD)
strcat (flagString, "HALFDEAD|");
if (btreeSection->btpo_flags & BTP_SPLIT_END)
strcat (flagString, "SPLITEND|");
if (btreeSection->btpo_flags & BTP_HAS_GARBAGE)
strcat (flagString, "HASGARBAGE|");
if (strlen (flagString))
flagString[strlen (flagString) - 1] = '\0';
printf (" BTree Index Section:\n"
" Flags: 0x%04x (%s)\n"
" Blocks: Previous (%d) Next (%d) %s (%d)\n\n",
" Blocks: Previous (%d) Next (%d) %s (%d) CycleId (%d)\n\n",
btreeSection->btpo_flags, flagString,
btreeSection->btpo_prev, btreeSection->btpo_next,
(btreeSection->
btpo_flags & BTP_DELETED) ? "Next XID" : "Level",
btreeSection->btpo.level);
btreeSection->btpo.level,
btreeSection->btpo_cycleid);
}
break;
// Hash index section
case SPEC_SECT_INDEX_HASH:
{
HashPageOpaque hashSection =
(HashPageOpaque) (buffer + specialOffset);
HashPageOpaque hashSection = (HashPageOpaque) (buffer + specialOffset);
if (hashSection->hasho_flag & LH_UNUSED_PAGE)
strcat (flagString, "UNUSED|");
if (hashSection->hasho_flag & LH_OVERFLOW_PAGE)
......@@ -928,6 +949,47 @@ FormatSpecial ()
}
break;
// GIST index section
case SPEC_SECT_INDEX_GIST:
{
GISTPageOpaque gistSection = (GISTPageOpaque) (buffer + specialOffset);
if (gistSection->flags & F_LEAF)
strcat (flagString, "LEAF|");
if (gistSection->flags & F_DELETED)
strcat (flagString, "DELETED|");
if (gistSection->flags & F_TUPLES_DELETED)
strcat (flagString, "TUPLESDELETED|");
if (strlen (flagString))
flagString[strlen (flagString) - 1] = '\0';
printf (" GIST Index Section:\n"
" Flags: 0x%08x (%s)\n"
" Blocks: RightLink (%d)\n\n",
gistSection->flags, flagString,
gistSection->rightlink);
}
break;
// GIN index section
case SPEC_SECT_INDEX_GIN:
{
GinPageOpaque ginSection = (GinPageOpaque) (buffer + specialOffset);
if (ginSection->flags & GIN_DATA)
strcat (flagString, "DATA|");
if (ginSection->flags & GIN_LEAF)
strcat (flagString, "LEAF|");
if (ginSection->flags & GIN_DELETED)
strcat (flagString, "DELETED|");
if (strlen (flagString))
flagString[strlen (flagString) - 1] = '\0';
printf (" GIN Index Section:\n"
" Flags: 0x%08x (%s) Maxoff: %d\n"
" Blocks: RightLink (%d)\n\n",
ginSection->flags, flagString,
ginSection->maxoff,
ginSection->rightlink);
}
break;
// No idea what type of special section this is
default:
printf (" Unknown special section type. Type: <%u>.\n", specialType);
......@@ -1027,8 +1089,11 @@ FormatControl ()
case DB_SHUTDOWNING:
dbState = "SHUTDOWNING";
break;
case DB_IN_RECOVERY:
dbState = "IN RECOVERY";
case DB_IN_CRASH_RECOVERY:
dbState = "IN CRASH RECOVERY";
break;
case DB_IN_ARCHIVE_RECOVERY:
dbState = "IN ARCHIVE RECOVERY";
break;
case DB_IN_PRODUCTION:
dbState = "IN PRODUCTION";
......
/*
* pg_filedump.h - PostgreSQL file dump utility for dumping and
* formatting heap(data), index and control files.
* Version 8.1.1 for PostgreSQL 8.1
* Version 8.2.0 for PostgreSQL 8.2
*
* Copyright (c) 2002, 2003, 2005 Red Hat, Inc. All rights reserved.
* Copyright (c) 2002-2007 Red Hat, Inc. All rights reserved.
*
* 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
......@@ -32,9 +32,9 @@
#include "postgres.h"
#include "storage/bufpage.h"
#include "access/hash.h"
#include "access/gin.h"
#include "access/gist.h"
#include "access/nbtree.h"
#include "access/rtree.h"
#include "access/itup.h"
#include "access/htup.h"
#include "catalog/pg_control.h"
......@@ -80,9 +80,10 @@ typedef enum
{
SPEC_SECT_NONE, // No special section on block
SPEC_SECT_SEQUENCE, // Sequence info in special section
SPEC_SECT_INDEX_RTREE, // RTree/GIST 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_GIST, // GIST index info in special section
SPEC_SECT_INDEX_GIN, // GIN index info in special section
SPEC_SECT_ERROR_UNKNOWN, // Unknown error
SPEC_SECT_ERROR_BOUNDARY // Boundary error
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment