openGauss-server/contrib/pagehack/pagehack.cpp

4547 lines
133 KiB
C++
Executable File

/*
* pagehack.cpp
*
* A simple hack program for PostgreSQL's internal files
* Originally written by Nicole Nie (coolnyy@gmail.com).
*
* contrib/pagehack/pagehack.cpp
* Copyright (c) 2000-2011, PostgreSQL Global Development Group
* ALL RIGHTS RESERVED;
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose, without fee, and without a written agreement
* is hereby granted, provided that the above copyright notice and this
* paragraph and the following two paragraphs appear in all copies.
*
* IN NO EVENT SHALL THE AUTHOR OR DISTRIBUTORS BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
* LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
* DOCUMENTATION, EVEN IF THE AUTHOR OR DISTRIBUTORS HAVE BEEN ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* THE AUTHOR AND DISTRIBUTORS SPECIFICALLY DISCLAIMS ANY WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE AUTHOR AND DISTRIBUTORS HAS NO OBLIGATIONS TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
*/
#ifdef WIN32
#define FD_SETSIZE 1024 /* set before winsock2.h is included */
#endif /* ! WIN32 */
/*
* We have to use postgres.h not postgres_fe.h here, because there's so much
* backend-only stuff in the XLOG include files we need. But we need a
* frontend-ish environment otherwise. Hence this ugly hack.
*/
#define FRONTEND 1
#include "postgres.h"
#include "knl/knl_variable.h"
#include <unistd.h>
#include <time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "access/heapam.h"
#include "access/htup.h"
#include "access/itup.h"
#include "access/nbtree.h"
#include "access/slru.h"
#include "access/twophase_rmgr.h"
#include "access/double_write.h"
#include "access/double_write_basic.h"
#include "catalog/pg_control.h"
#include "catalog/pg_attribute.h"
#include "catalog/pg_class.h"
#include "catalog/pg_statistic.h"
#include "catalog/pg_index.h"
#include "catalog/pg_database.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_resource_pool.h"
#include "catalog/pg_partition.h"
#include "catalog/pgxc_group.h"
#include "catalog/pgxc_node.h"
#include "commands/dbcommands.h"
#include "replication/slot.h"
#include "storage/buf/bufpage.h"
#include "storage/lock/lock.h"
#include "storage/proc.h"
#include "storage/relfilenode.h"
#include "storage/sinval.h"
#include "replication/bcm.h"
#include "utils/datetime.h"
#include "utils/memutils.h"
#include "utils/relmapper.h"
#include "utils/timestamp.h"
#include "cstore.h"
#include "common/build_query/build_query.h"
#include "tsdb/utils/constant_def.h"
/* Max number of pg_class oid, currently about 4000 */
#define MAX_PG_CLASS_ID 10000
/* Number of pg_class types */
#define CLASS_TYPE_NUM 512
typedef unsigned char* binary;
static const char* indents[] = { // 10 tab is enough to used.
"",
"\t",
"\t\t",
"\t\t\t",
"\t\t\t\t",
"\t\t\t\t\t",
"\t\t\t\t\t\t",
"\t\t\t\t\t\t\t",
"\t\t\t\t\t\t\t\t",
"\t\t\t\t\t\t\t\t\t",
"\t\t\t\t\t\t\t\t\t\t"};
static const int nIndents = sizeof(indents) / sizeof(indents[0]);
static int indentLevel = 0;
static HeapTupleData dummyTuple;
// add those special tables to parse, so we can read the tuple data
//
typedef void (*ParseHeapTupleData)(binary tup, int len, binary nullBitmap, int natrrs);
static const char* PgBtreeIndexRelName[] = {"toast_index"};
static const char* PgHeapRelName[] = {"pg_class",
"pg_index",
"pg_partition",
"pg_cudesc_xx", // all the relations about pg_cudesc_xx kind, not the real pg_cudesc table
"ts_cudesc_xx",
"pg_database",
"pg_tablespace",
"pg_attribute",
"pg_am",
"pg_statistic",
"pg_toast"};
static void ParsePgClassTupleData(binary tupdata, int len, binary nullBitmap, int natrrs);
static void ParsePgIndexTupleData(binary tupdata, int len, binary nullBitmap, int nattrs);
static void ParsePgPartitionTupleData(binary tupdata, int len, binary nullBitmap, int natrrs);
static void ParsePgCudescXXTupleData(binary tupdata, int len, binary nullBitmap, int natrrs);
static void ParseTsCudescXXTupleData(binary tupdata, int len, binary nullBitmap, int nattrs);
static void ParsePgDatabaseTupleData(binary tupdata, int len, binary nullBitmap, int nattrs);
static void ParsePgTablespaceTupleData(binary tupdata, int len, binary nullBitmap, int nattrs);
static void ParsePgAttributeTupleData(binary tupdata, int len, binary nullBitmap, int nattrs);
static void ParsePgAmTupleData(binary tupdata, int len, binary nullBitmap, int nattrs);
static void ParsePgstatisticTupleData(binary tupdata, int len, binary nullBitmap, int nattrs);
static void ParseToastTupleData(binary tupdata, int len, binary nullBitmap, int nattrs);
static void ParseToastIndexTupleData(binary tupdata, int len, binary nullBitmap, int nattrs);
static ParseHeapTupleData PgHeapRelTupleParser[] = {
ParsePgClassTupleData, // pg_class
ParsePgIndexTupleData, // pg_index
ParsePgPartitionTupleData, // pg_partition
ParsePgCudescXXTupleData, // pg_cudesc_xx
ParseTsCudescXXTupleData, // ts_cudesc_xx
ParsePgDatabaseTupleData, // pg_database
ParsePgTablespaceTupleData, // pg_tablespace
ParsePgAttributeTupleData, // pg_attribute
ParsePgAmTupleData // pg_am
,
ParsePgstatisticTupleData // pg_statistic
,
ParseToastTupleData // pg_toast
};
static ParseHeapTupleData PgIndexRelTupleParser[] = {ParseToastIndexTupleData};
static int PgHeapRelTupleParserCursor = -1;
static int PgIndexRelTupleParserCursor = -1;
/* For Assert(...) macros. */
THR_LOCAL bool assert_enabled = true;
/* Options */
bool only_vm = false;
bool only_bcm = false;
bool write_back = false;
bool dirty_page = false;
int start_item = 1;
int num_item = 0;
bool vm_cache[BLCKSZ] = {false};
/*
* MaxLevelNum can not exceed 0x0F
*/
#define MaxLevelNumInternal 5
static const int freespaceThreshold[MaxLevelNumInternal] = {
0, /* used 96% ~ 100% */
MaxHeapTupleSize * 4 / 100, /* used 81% ~ 95% */
MaxHeapTupleSize * 1 / 5, /* used 51% ~ 80% */
MaxHeapTupleSize / 2, /* used 1% ~ 50% */
MaxHeapTupleSize /* not used */
};
/* table for fast counting of bcm bits */
static const uint8 number_of_bcm_bits[256] = {0,
0,
1,
1,
0,
0,
1,
1,
1,
1,
2,
2,
1,
1,
2,
2,
0,
0,
1,
1,
0,
0,
1,
1,
1,
1,
2,
2,
1,
1,
2,
2,
1,
1,
2,
2,
1,
1,
2,
2,
2,
2,
3,
3,
2,
2,
3,
3,
1,
1,
2,
2,
1,
1,
2,
2,
2,
2,
3,
3,
2,
2,
3,
3,
0,
0,
1,
1,
0,
0,
1,
1,
1,
1,
2,
2,
1,
1,
2,
2,
0,
0,
1,
1,
0,
0,
1,
1,
1,
1,
2,
2,
1,
1,
2,
2,
1,
1,
2,
2,
1,
1,
2,
2,
2,
2,
3,
3,
2,
2,
3,
3,
1,
1,
2,
2,
1,
1,
2,
2,
2,
2,
3,
3,
2,
2,
3,
3,
1,
1,
2,
2,
1,
1,
2,
2,
2,
2,
3,
3,
2,
2,
3,
3,
1,
1,
2,
2,
1,
1,
2,
2,
2,
2,
3,
3,
2,
2,
3,
3,
2,
2,
3,
3,
2,
2,
3,
3,
3,
3,
4,
4,
3,
3,
4,
4,
2,
2,
3,
3,
2,
2,
3,
3,
3,
3,
4,
4,
3,
3,
4,
4,
1,
1,
2,
2,
1,
1,
2,
2,
2,
2,
3,
3,
2,
2,
3,
3,
1,
1,
2,
2,
1,
1,
2,
2,
2,
2,
3,
3,
2,
2,
3,
3,
2,
2,
3,
3,
2,
2,
3,
3,
3,
3,
4,
4,
3,
3,
4,
4,
2,
2,
3,
3,
2,
2,
3,
3,
3,
3,
4,
4,
3,
3,
4,
4};
/* table for fast counting of meta bits */
static const uint8 number_of_meta_bits[256] = {0,
0,
1,
1,
0,
0,
1,
1,
0,
0,
1,
1,
0,
0,
1,
1,
0,
0,
1,
1,
0,
0,
1,
1,
0,
0,
1,
1,
0,
0,
1,
1,
1,
1,
2,
2,
1,
1,
2,
2,
1,
1,
2,
2,
1,
1,
2,
2,
1,
1,
2,
2,
1,
1,
2,
2,
1,
1,
2,
2,
1,
1,
2,
2,
0,
0,
1,
1,
0,
0,
1,
1,
0,
0,
1,
1,
0,
0,
1,
1,
0,
0,
1,
1,
0,
0,
1,
1,
0,
0,
1,
1,
0,
0,
1,
1,
1,
1,
2,
2,
1,
1,
2,
2,
1,
1,
2,
2,
1,
1,
2,
2,
1,
1,
2,
2,
1,
1,
2,
2,
1,
1,
2,
2,
1,
1,
2,
2,
0,
0,
1,
1,
0,
0,
1,
1,
0,
0,
1,
1,
0,
0,
1,
1,
0,
0,
1,
1,
0,
0,
1,
1,
0,
0,
1,
1,
0,
0,
1,
1,
1,
1,
2,
2,
1,
1,
2,
2,
1,
1,
2,
2,
1,
1,
2,
2,
1,
1,
2,
2,
1,
1,
2,
2,
1,
1,
2,
2,
1,
1,
2,
2,
0,
0,
1,
1,
0,
0,
1,
1,
0,
0,
1,
1,
0,
0,
1,
1,
0,
0,
1,
1,
0,
0,
1,
1,
0,
0,
1,
1,
0,
0,
1,
1,
1,
1,
2,
2,
1,
1,
2,
2,
1,
1,
2,
2,
1,
1,
2,
2,
1,
1,
2,
2,
1,
1,
2,
2,
1,
1,
2,
2,
1,
1,
2,
2};
uint32 pg_checksum_block(char* data, uint32 size)
{
uint32 sums[N_SUMS];
uint32(*dataArr)[N_SUMS] = (uint32(*)[N_SUMS])data;
uint32 result = 0;
errno_t rc;
uint32 i, j;
/* ensure that the size is compatible with the algorithm */
Assert((size % (sizeof(uint32) * N_SUMS)) == 0);
/* initialize partial checksums to their corresponding offsets */
rc = memcpy_s(sums, sizeof(sums), g_checksumBaseOffsets, sizeof(g_checksumBaseOffsets));
securec_check(rc, "", "");
/* main checksum calculation */
for (i = 0; i < size / sizeof(uint32) / N_SUMS; i++) {
for (j = 0; j < N_SUMS; j++) {
CHECKSUM_COMP(sums[j], dataArr[i][j]);
}
}
/* finally add in two rounds of zeroes for additional mixing */
for (i = 0; i < CHECKSUM_CACL_ROUNDS; i++) {
for (j = 0; j < N_SUMS; j++) {
CHECKSUM_COMP(sums[j], 0);
}
}
/* xor fold partial checksums together */
for (i = 0; i < N_SUMS; i++) {
result ^= sums[i];
}
return result;
}
uint16 pg_checksum_page(char* page, BlockNumber blkno)
{
PageHeader phdr = (PageHeader)page;
uint16 save_checksum;
uint32 checksum;
/*
* Save pd_checksum and temporarily set it to zero, so that the checksum
* calculation isn't affected by the old checksum stored on the page.
* Restore it after, because actually updating the checksum is NOT part of
* the API of this function.
*/
save_checksum = phdr->pd_checksum;
phdr->pd_checksum = 0;
checksum = pg_checksum_block(page, BLCKSZ);
phdr->pd_checksum = save_checksum;
/* Mix in the block number to detect transposed pages */
checksum ^= blkno;
/*
* Reduce to a uint16 (to fit in the pd_checksum field) with an offset of
* one. That avoids checksums of zero, which seems like a good idea.
*/
return (checksum % UINT16_MAX) + 1;
}
/*
* SpaceGetBlockFreeLevel
* Returns the block free level according to freespace.
*/
#define BlockFreeLevelGetSpaceInternal(level) (freespaceThreshold[(level)])
void ExceptionalCondition(const char* conditionName, const char* errorType, const char* fileName, int lineNumber)
{
fprintf(stderr, "TRAP: %s(\"%s\", File: \"%s\", Line: %d)\n", errorType, conditionName, fileName, lineNumber);
abort();
}
// see to relmappper.cpp
//
#define MAX_MAPPINGS 62 /* 62 * 8 + 16 = 512 */
#define RELMAPPER_FILENAME "pg_filenode.map"
#define RELMAPPER_FILEMAGIC 0x592717 /* version ID value */
#define RELCACHE_INIT_FILEMAGIC 0x573266 /* version ID value */
typedef struct PgClass_table {
const char* class_name;
Oid ralation_id;
} PgClass_table;
typedef struct TwoPhaseRecordOnDisk {
uint32 len; /* length of rmgr data */
TwoPhaseRmgrId rmid; /* resource manager for this record */
uint16 info; /* flag bits for use by rmgr */
} TwoPhaseRecordOnDisk;
typedef struct TwoPhaseLockRecord {
LOCKTAG locktag;
LOCKMODE lockmode;
} TwoPhaseLockRecord;
typedef struct TwoPhaseFileHeader {
uint32 magic; /* format identifier */
uint32 total_len; /* actual file length */
TransactionId xid; /* original transaction XID */
Oid database; /* OID of database it was in */
TimestampTz prepared_at; /* time of preparation */
Oid owner; /* user running the transaction */
int32 nsubxacts; /* number of following subxact XIDs */
int32 ncommitrels; /* number of delete-on-commit rels */
int32 nabortrels; /* number of delete-on-abort rels */
int32 ninvalmsgs; /* number of cache invalidation messages */
bool initfileinval; /* does relcache init file need invalidation? */
char gid[200]; /* GID for transaction */
} TwoPhaseFileHeader;
#ifndef WIN32
#include <sys/time.h>
#include <unistd.h>
#endif /* ! WIN32 */
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#ifdef HAVE_SYS_RESOURCE_H
#include <sys/resource.h> /* for getrlimit */
#endif
#ifndef INT64_MAX
#define INT64_MAX INT64CONST(0x7FFFFFFFFFFFFFFF)
#endif
typedef enum HackingType {
HACKING_HEAP, /* heap page */
HACKING_INDEX, /* index page */
HACKING_UNDO, /* undo page */
HACKING_FILENODE,
HACKING_INTERNAL_INIT, /* pg_internal.init */
HACKING_TWOPHASE, /* two phase file */
HACKING_CU, /* cu page */
HACKING_SLOT,
HACKING_CONTROL,
HACKING_CLOG,
HACKING_CSNLOG,
HACKING_STATE,
HACKING_DW,
HACKING_DW_SINGLE,
NUM_HACKINGTYPE
} HackingType;
static HackingType hackingtype = HACKING_HEAP;
static const char* HACKINGTYPE[] = {"heap",
"btree_index",
"undo",
"filenode_map",
"pg_internal_init",
"twophase",
"cu",
"slot",
"pg_control",
"clog",
"csnlog",
"gaussdb_state",
"double_write",
"dw_single_flush_file"};
typedef enum SegmentType { SEG_HEAP, SEG_INDEX_BTREE, SEG_UNDO, SEG_UNKNOWN } SegmentType;
const char* PageTypeNames[] = {"DATA", "FSM", "VM"};
#define GETHEAPSTRUCT(TUP) ((unsigned char*)(TUP) + (TUP)->t_hoff)
#define GETINDEXSTRUCT(ITUP) ((unsigned char*)(ITUP) + IndexInfoFindDataOffset((ITUP)->t_info))
extern char* optarg;
extern int optind;
char* pgdata = NULL;
static void fill_filenode_map(char** class_map);
static const char HexCharMaps[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
#define Byte2HexChar(_buff, _byte) \
do { \
(_buff)[0] = HexCharMaps[(_byte) >> 4]; \
(_buff)[1] = HexCharMaps[(_byte)&0x0F]; \
} while (0)
/* PG */
#define CLOG_BITS_PER_XACT 2
#define CLOG_XACTS_PER_BYTE 4
#define CLOG_XACTS_PER_PAGE (BLCKSZ * CLOG_XACTS_PER_BYTE)
#define CLOG_XACT_BITMASK ((1 << CLOG_BITS_PER_XACT) - 1)
#define CSNLOG_XACTS_PER_PAGE (BLCKSZ / sizeof(CommitSeqNo))
#define TransactionIdToPage(xid) ((xid) / (TransactionId)CLOG_XACTS_PER_PAGE)
#define TransactionIdToPgIndex(xid) ((xid) % (TransactionId)CLOG_XACTS_PER_PAGE)
#define TransactionIdToByte(xid) (TransactionIdToPgIndex(xid) / CLOG_XACTS_PER_BYTE)
#define TransactionIdToBIndex(xid) ((xid) % (TransactionId)CLOG_XACTS_PER_BYTE)
static void formatBytes(unsigned char* start, int len)
{
#ifdef DEBUG
int cnt;
char byteBuf[4] = {0, 0, ' ', '\0'};
unsigned char ch;
int bytesEachLine = 32;
// set the indent-level first
++indentLevel;
for (cnt = 0; cnt < len; cnt++) {
ch = (unsigned char)*start;
start++;
// print 32bytes each line
if (bytesEachLine == 32) {
fprintf(stdout, "\n%s", indents[indentLevel]);
bytesEachLine = 0;
} else if (bytesEachLine % 8 == 0) {
fprintf(stdout, " ");
}
++bytesEachLine;
Byte2HexChar(byteBuf, ch);
fprintf(stdout, "%s", byteBuf);
}
--indentLevel;
#endif
}
static void formatBitmap(const unsigned char* start, int len, char bit1, char bit0)
{
int bytesOfOneLine = 8;
++indentLevel;
for (int i = 0; i < len; ++i) {
unsigned char ch = start[i];
unsigned char bitmask = 1;
// print 8bytes each line
if (bytesOfOneLine == 8) {
fprintf(stdout, "\n%s", indents[indentLevel]);
bytesOfOneLine = 0;
}
++bytesOfOneLine;
// print 8 bits within a loop
do {
fprintf(stdout, "%c", ((ch & bitmask) ? bit1 : bit0));
bitmask <<= 1;
} while (bitmask != 0);
fprintf(stdout, " ");
}
--indentLevel;
}
static void usage(const char* progname)
{
printf("%s is a hacking tool for PostgreSQL.\n"
"\n"
"Usage:\n"
" %s [OPTIONS]\n"
"\nHacking options:\n"
" -f FILENAME the database file to hack\n",
progname,
progname);
// print supported type within HACKINGTYPE[]
//
printf(" -t {");
int nTypes = sizeof(HACKINGTYPE) / sizeof(HACKINGTYPE[0]);
for (int i = 0; i < nTypes; ++i) {
printf(" %s%s", HACKINGTYPE[i], (i == nTypes - 1) ? " " : "|");
}
printf("}\n"
" the hacking type (default: heap)\n");
// print supported table name for HEAP type
//
printf(" -r {");
int nrel = (int)sizeof(PgHeapRelName) / sizeof(PgHeapRelName[0]);
for (int i = 0; i < nrel; ++i) {
printf(" %s%s", PgHeapRelName[i], (i == nrel - 1) ? " " : "|");
}
printf("} given relation name when -t is heap \n");
// print supported table name for INDEX type
//
printf(" -i {");
nrel = (int)sizeof(PgBtreeIndexRelName) / sizeof(PgBtreeIndexRelName[0]);
for (int i = 0; i < nrel; ++i) {
printf(" %s%s", PgBtreeIndexRelName[i], (i == nrel - 1) ? " " : "|");
}
printf("} given relation name when -t is btree_index \n");
printf(" -v only show visibility map info, can only work when parsing index or heap\n"
" -b only show BCM map info, can only work when parsing index or heap\n"
" -u double write hacking\n"
" -s set the start point to hack when hacking heap/index/undo\n"
" -n set the number of blocks to hack\n"
" -o set the CU pointer from cudesc\n"
" -I set the start item slot need change in one page\n"
" -N set the number slots need change in one page \n"
" -w write the change to file\n"
" -d only for test, use 0xFF to fill the last half page[4k]\n"
"\nCommon options:\n"
" --help, -h show this help, then exit\n"
" --version, -V output version information, then exit\n"
"\n"
"Report bugs to <pgsql-bugs@postgresql.org>.\n");
}
static bool HexStringToInt(char* hex_string, int* result)
{
int num = 0;
char* temp = hex_string;
int onechar = 0;
int index = 0;
if (NULL == hex_string)
return false;
while (*temp++ != '\0')
num++;
while (num--) {
if (hex_string[num] >= 'A' && hex_string[num] <= 'F')
onechar = hex_string[num] - 55;
else if (hex_string[num] >= '0' && hex_string[num] <= '9')
onechar = hex_string[num] - 48;
else
return false;
*result += onechar << (index * 4);
index++;
}
return true;
}
static void ParsePgCudescXXTupleData(binary tupdata, int len, binary nullBitmap, int nattrs)
{
if (nattrs != CUDescCUExtraAttr) {
fprintf(stdout, "invalid attributes number, expected %d, result %d", CUDescCUExtraAttr, nattrs);
exit(1);
}
int datlen = 0;
char* dat = NULL;
char* nextAttr = (char*)tupdata;
bool isnulls[nattrs];
memset(isnulls, false, nattrs);
if (NULL != nullBitmap) {
datlen = (nattrs + 7) / 8;
int j = 0;
for (int i = 0; i < datlen; ++i) {
unsigned char ch = nullBitmap[i];
unsigned char bitmask = 1;
do {
isnulls[j] = (ch & bitmask) ? false : true;
bitmask <<= 1;
++j;
} while (bitmask != 0 && j < nattrs);
}
}
indentLevel = 4;
if (!isnulls[0]) {
nextAttr = (char*)att_align_nominal((long int)nextAttr, 'i');
fprintf(stdout,
"\n%s"
"ColId: %d",
indents[indentLevel],
*(int32*)nextAttr);
nextAttr += sizeof(int32);
}
if (!isnulls[1]) {
nextAttr = (char*)att_align_nominal((long int)nextAttr, 'i');
fprintf(stdout,
"\n%s"
"CUId: %ud",
indents[indentLevel],
*(uint32*)nextAttr);
nextAttr += sizeof(uint32);
}
if (!isnulls[2]) {
// rough check MIN/MAX
nextAttr = (char*)att_align_pointer((long int)nextAttr, 'i', -1, nextAttr);
datlen = VARSIZE_ANY_EXHDR(nextAttr);
Assert(datlen >= 0 && datlen < 32);
dat = VARDATA_ANY(nextAttr);
Assert(dat == nextAttr + 1 || dat == nextAttr + 4);
fprintf(stdout,
"\n%s"
"MIN size: %d",
indents[indentLevel],
datlen);
#ifdef DEBUG
fprintf(stdout,
"\n%s"
"data are:",
indents[indentLevel]);
formatBytes((unsigned char*)dat, datlen);
#endif
nextAttr += datlen + int(dat - nextAttr);
}
if (!isnulls[3]) {
nextAttr = (char*)att_align_pointer((long int)nextAttr, 'i', -1, nextAttr);
datlen = VARSIZE_ANY_EXHDR(nextAttr);
Assert(datlen >= 0 && datlen < 32);
dat = VARDATA_ANY(nextAttr);
Assert(dat == nextAttr + 1 || dat == nextAttr + 4);
fprintf(stdout,
"\n%s"
"MAX size: %d",
indents[indentLevel],
datlen);
#ifdef DEBUG
fprintf(stdout,
"\n%s"
"data are:",
indents[indentLevel]);
formatBytes((unsigned char*)dat, datlen);
#endif
nextAttr += datlen + int(dat - nextAttr);
}
if (!isnulls[4]) {
nextAttr = (char*)att_align_nominal((long int)nextAttr, 'i');
fprintf(stdout,
"\n%s"
"rows: %d",
indents[indentLevel],
*(int32*)nextAttr);
nextAttr += sizeof(int32);
}
if (!isnulls[5]) {
nextAttr = (char*)att_align_nominal((long int)nextAttr, 'i');
fprintf(stdout,
"\n%s"
"mode: %x",
indents[indentLevel],
*(uint32*)nextAttr);
nextAttr += sizeof(uint32);
}
if (!isnulls[6]) {
nextAttr = (char*)att_align_nominal((long int)nextAttr, 'd');
fprintf(stdout,
"\n%s"
"cu size: %d",
indents[indentLevel],
*(int32*)nextAttr);
nextAttr += sizeof(int64);
}
if (!isnulls[7]) {
// CU Pointer
nextAttr = (char*)att_align_pointer((long int)nextAttr, 'i', -1, nextAttr);
datlen = VARSIZE_ANY_EXHDR(nextAttr);
dat = VARDATA_ANY(nextAttr);
if (datlen >= 0 && datlen <= (int)sizeof(uint64)) {
fprintf(stdout,
"\n%s"
"cu pointer: %lu, sizeof: %d",
indents[indentLevel],
*(uint64*)dat,
datlen);
} else {
fprintf(stdout,
"\n%s"
"cu pointer bitmap: %d",
indents[indentLevel],
datlen);
#ifdef DEBUG
fprintf(stdout,
"\n%s"
"data are:",
indents[indentLevel]);
formatBytes((unsigned char*)dat, datlen);
#endif
}
nextAttr += datlen + int(dat - nextAttr);
}
if (!isnulls[8]) {
nextAttr = (char*)att_align_nominal((long int)nextAttr, 'i');
fprintf(stdout,
"\n%s"
"cu magic: %u",
indents[indentLevel],
*(uint32*)nextAttr);
nextAttr += sizeof(uint32);
}
Assert(len >= int(nextAttr - (char*)tupdata));
}
static void ParseTsCudescXXTupleData(binary tupdata, int len, binary nullBitmap, int nattrs)
{
if (nattrs != TsCudesc::MAX_ATT_NUM) {
fprintf(stdout, "invalid attributes number, expected %d, result %d", TsCudesc::MAX_ATT_NUM, nattrs);
exit(1);
}
int datlen = 0;
int j = 0;
int i = 0;
char* dat = NULL;
char* nextAttr = (char*)tupdata;
unsigned char ch = 0;
unsigned char bitmask = 0;
bool isnulls[nattrs] = {0};
if (NULL != nullBitmap) {
datlen = (nattrs + 7) / 8;
j = 0;
for (i = 0; i < datlen; ++i) {
ch = nullBitmap[i];
bitmask = 1;
do {
isnulls[j] = (ch & bitmask) ? false : true;
bitmask <<= 1;
++j;
} while (bitmask != 0 && j < nattrs);
}
}
indentLevel = 4;
if (!isnulls[0]) {
nextAttr = (char*)att_align_nominal((long int)nextAttr, 'i');
fprintf(stdout, "\n%s" "ColId: %d", indents[indentLevel], *(int32*)nextAttr);
nextAttr += sizeof(int32);
}
if (!isnulls[1]) {
nextAttr = (char*)att_align_nominal((long int)nextAttr, 'i');
fprintf(stdout, "\n%s" "TagId: %d", indents[indentLevel], *(int32*)nextAttr);
nextAttr += sizeof(int32);
}
if (!isnulls[2]) {
nextAttr = (char*)att_align_nominal((long int)nextAttr, 'i');
fprintf(stdout, "\n%s" "CUId: %u", indents[indentLevel], *(uint32*)nextAttr);
nextAttr += sizeof(uint32);
}
if (!isnulls[3]) {
// rough check MIN/MAX
nextAttr = (char*)att_align_pointer((long int)nextAttr, 'i', -1, nextAttr);
datlen = VARSIZE_ANY_EXHDR(nextAttr);
Assert(datlen < 32 && datlen >= 0);
dat = VARDATA_ANY(nextAttr);
Assert(dat == nextAttr + 4 || dat == nextAttr + 1);
fprintf(stdout, "\n%s" "MIN size: %d", indents[indentLevel], datlen);
#ifdef DEBUG
fprintf(stdout, "\n%s" "data are:", indents[indentLevel]);
formatBytes((unsigned char*)dat, datlen);
#endif
nextAttr += datlen + int(dat - nextAttr);
}
if (!isnulls[4]) {
nextAttr = (char*)att_align_pointer((long int)nextAttr, 'i', -1, nextAttr);
datlen = VARSIZE_ANY_EXHDR(nextAttr);
Assert(datlen < 32 && datlen >= 0);
dat = VARDATA_ANY(nextAttr);
Assert(dat == nextAttr + 4 || dat == nextAttr + 1);
fprintf(stdout, "\n%s" "MAX size: %d", indents[indentLevel], datlen);
#ifdef DEBUG
fprintf(stdout, "\n%s" "data are:", indents[indentLevel]);
formatBytes((unsigned char*)dat, datlen);
#endif
nextAttr = nextAttr + datlen + int(dat - nextAttr);
}
if (!isnulls[5]) {
nextAttr = (char*)att_align_nominal((long int)nextAttr, 'i');
fprintf(stdout, "\n%s" "rows: %d", indents[indentLevel], *(int32*)nextAttr);
nextAttr = nextAttr + sizeof(int32);
}
if (!isnulls[6]) {
nextAttr = (char*)att_align_nominal((long int)nextAttr, 'i');
fprintf(stdout, "\n%s" "mode: %x", indents[indentLevel], *(uint32*)nextAttr);
nextAttr = nextAttr + sizeof(int32);
}
if (!isnulls[7]) {
nextAttr = (char*)att_align_nominal((long int)nextAttr, 'd');
fprintf(stdout, "\n%s" "cu size: %d", indents[indentLevel], *(int32*)nextAttr);
nextAttr = nextAttr + sizeof(int64);
}
if (!isnulls[8]) {
// CU Pointer
nextAttr = (char*)att_align_pointer((long int)nextAttr, 'i', -1, nextAttr);
datlen = VARSIZE_ANY_EXHDR(nextAttr);
dat = VARDATA_ANY(nextAttr);
if (datlen >= 0 && datlen <= (int)sizeof(uint64)) {
fprintf(stdout, "\n%s" "cu pointer: %lu, sizeof: %d",
indents[indentLevel], *(uint64*)dat, datlen);
} else {
fprintf(stdout,"\n%s" "cu pointer bitmap: %d",
indents[indentLevel], datlen);
#ifdef DEBUG
fprintf(stdout, "\n%s" "data are:", indents[indentLevel]);
formatBytes((unsigned char*)dat, datlen);
#endif
}
nextAttr = nextAttr + datlen + int(dat - nextAttr);
}
if (!isnulls[9]) {
nextAttr = (char*)att_align_nominal((long int)nextAttr, 'i');
fprintf(stdout, "\n%s" "cu magic: %u", indents[indentLevel], *(uint32*)nextAttr);
nextAttr = nextAttr + sizeof(uint32);
}
Assert(len >= int(nextAttr - (char*)tupdata));
}
// parse and print tuple data in PG_PARTITION relation
//
static void ParsePgPartitionTupleData(binary tupdata, int len, binary nullBitmap, int nattrs)
{
if (nattrs != Natts_pg_partition) {
fprintf(stdout, "invalid attributes number, expected %d, result %d", Natts_pg_partition, nattrs);
exit(1);
}
Form_pg_partition pgPartitionTupData = (Form_pg_partition)tupdata;
indentLevel = 3;
fprintf(stdout,
"\n%s"
"name: %s",
indents[indentLevel],
(pgPartitionTupData->relname.data));
fprintf(stdout,
"\n%s"
"part type: %c",
indents[indentLevel],
pgPartitionTupData->parttype);
fprintf(stdout,
"\n%s"
"parent id: %u",
indents[indentLevel],
pgPartitionTupData->parentid);
fprintf(stdout,
"\n%s"
"range num: %d",
indents[indentLevel],
pgPartitionTupData->rangenum);
fprintf(stdout,
"\n%s"
"intervalnum: %d",
indents[indentLevel],
pgPartitionTupData->intervalnum);
fprintf(stdout,
"\n%s"
"partstrategy: %c",
indents[indentLevel],
pgPartitionTupData->partstrategy);
fprintf(stdout,
"\n%s"
"relfilenode: %u",
indents[indentLevel],
pgPartitionTupData->relfilenode);
fprintf(stdout,
"\n%s"
"reltablespace: %u",
indents[indentLevel],
pgPartitionTupData->reltablespace);
fprintf(stdout,
"\n%s"
"relpages: %f",
indents[indentLevel],
pgPartitionTupData->relpages);
fprintf(stdout,
"\n%s"
"reltuples: %f",
indents[indentLevel],
pgPartitionTupData->reltuples);
fprintf(stdout,
"\n%s"
"relallvisible: %d",
indents[indentLevel],
pgPartitionTupData->relallvisible);
fprintf(stdout,
"\n%s"
"reltoastrelid: %u",
indents[indentLevel],
pgPartitionTupData->reltoastrelid);
fprintf(stdout,
"\n%s"
"reltoastidxid: %u",
indents[indentLevel],
pgPartitionTupData->reltoastidxid);
fprintf(stdout,
"\n%s"
"indextblid: %u",
indents[indentLevel],
pgPartitionTupData->indextblid);
fprintf(stdout,
"\n%s"
"indisusable: %d",
indents[indentLevel],
pgPartitionTupData->indisusable);
fprintf(stdout,
"\n%s"
"reldeltarelid: %u",
indents[indentLevel],
pgPartitionTupData->reldeltarelid);
fprintf(stdout,
"\n%s"
"reldeltaidx: %u",
indents[indentLevel],
pgPartitionTupData->reldeltaidx);
fprintf(stdout,
"\n%s"
"relcudescrelid: %u",
indents[indentLevel],
pgPartitionTupData->relcudescrelid);
fprintf(stdout,
"\n%s"
"relcudescidx: %u",
indents[indentLevel],
pgPartitionTupData->relcudescidx);
fprintf(stdout,
"\n%s"
"relfrozenxid: %u",
indents[indentLevel],
pgPartitionTupData->relfrozenxid);
fprintf(stdout,
"\n%s"
"intspnum: %d",
indents[indentLevel],
pgPartitionTupData->intspnum);
#ifdef DEBUG
int remain = len - PARTITION_TUPLE_SIZE;
if (remain > 0) {
if (remain - sizeof(TransactionId) > 0) {
fprintf(stdout, "\n%sthe others:", indents[indentLevel]);
formatBytes(tupdata + (len - remain), remain - sizeof(TransactionId));
fprintf(stdout, "\n%srelfrozenxid64: ", indents[indentLevel]);
formatBytes(tupdata + (len - remain + sizeof(TransactionId)), sizeof(TransactionId));
} else if (remain - sizeof(TransactionId) == 0) {
fprintf(stdout, "\n%srelfrozenxid64: ", indents[indentLevel]);
formatBytes(tupdata + (len - remain), sizeof(TransactionId));
} else {
fprintf(stdout, "\n%sthe others:", indents[indentLevel]);
formatBytes(tupdata + (len - remain), remain);
}
}
#endif
fprintf(stdout, "\n");
}
static void ParseToastIndexTupleData(binary tupdata, int len, binary nullBitmap, int nattrs)
{
int* values = (int*)tupdata;
indentLevel = 3;
if (len > 0) {
fprintf(stdout,
"\n%s"
"unique_id: %u",
indents[indentLevel],
*values++);
fprintf(stdout,
"\n%s"
"chunk_seq: %u",
indents[indentLevel],
*values++);
}
}
// parse and print tuple data in PG_TOAST relation
//
static void ParseToastTupleData(binary tupdata, int len, binary nullBitmap, int nattrs)
{
int* values = (int*)tupdata;
indentLevel = 3;
fprintf(stdout,
"\n%s"
"unique_id: %u",
indents[indentLevel],
*values++);
fprintf(stdout,
"\n%s"
"chunk_seq: %u",
indents[indentLevel],
*values++);
}
// parse and print tuple data in PG_STATISTIC relation
//
static void ParsePgstatisticTupleData(binary tupdata, int len, binary nullBitmap, int nattrs)
{
if (nattrs != Natts_pg_statistic) {
fprintf(stdout, "invalid attributes number, expected %d, result %d", Natts_pg_statistic, nattrs);
exit(1);
}
Form_pg_statistic pgStatTupData = (Form_pg_statistic)tupdata;
indentLevel = 3;
fprintf(stdout,
"\n%s"
"starelid: %u",
indents[indentLevel],
(pgStatTupData->starelid));
fprintf(stdout,
"\n%s"
"starelkind: %c",
indents[indentLevel],
(pgStatTupData->starelkind));
fprintf(stdout,
"\n%s"
"staattnum: %d",
indents[indentLevel],
(pgStatTupData->staattnum));
fprintf(stdout,
"\n%s"
"stainherit: %d",
indents[indentLevel],
(pgStatTupData->stainherit));
fprintf(stdout,
"\n%s"
"stanullfrac: %f",
indents[indentLevel],
(pgStatTupData->stanullfrac));
fprintf(stdout,
"\n%s"
"stawidth: %d",
indents[indentLevel],
(pgStatTupData->stawidth));
fprintf(stdout,
"\n%s"
"stadistinct: %f",
indents[indentLevel],
(pgStatTupData->stadistinct));
fprintf(stdout,
"\n%s"
"stakind1: %d",
indents[indentLevel],
(pgStatTupData->stakind1));
fprintf(stdout,
"\n%s"
"stakind2: %d",
indents[indentLevel],
(pgStatTupData->stakind2));
fprintf(stdout,
"\n%s"
"stakind3: %d",
indents[indentLevel],
(pgStatTupData->stakind3));
fprintf(stdout,
"\n%s"
"stakind4: %d",
indents[indentLevel],
(pgStatTupData->stakind4));
fprintf(stdout,
"\n%s"
"stakind5: %d",
indents[indentLevel],
(pgStatTupData->stakind5));
fprintf(stdout,
"\n%s"
"staop1: %u",
indents[indentLevel],
(pgStatTupData->staop1));
fprintf(stdout,
"\n%s"
"staop2: %u",
indents[indentLevel],
(pgStatTupData->staop2));
fprintf(stdout,
"\n%s"
"staop3: %u",
indents[indentLevel],
(pgStatTupData->staop3));
fprintf(stdout,
"\n%s"
"staop4: %u",
indents[indentLevel],
(pgStatTupData->staop4));
fprintf(stdout,
"\n%s"
"staop5: %u",
indents[indentLevel],
(pgStatTupData->staop5));
fprintf(stdout, "\n");
}
// parse and print tuple data in PG_CLASS relation
//
static void ParsePgClassTupleData(binary tupdata, int len, binary nullBitmap, int nattrs)
{
if (nattrs != Natts_pg_class) {
fprintf(stdout, "invalid attributes number, expected %d, result %d", Natts_pg_class, nattrs);
exit(1);
}
Form_pg_class pgClassTupData = (Form_pg_class)tupdata;
indentLevel = 3;
#ifdef DEBUG
fprintf(stdout,
"\n%s"
"name: %s",
indents[indentLevel],
(pgClassTupData->relname.data));
#endif
fprintf(stdout,
"\n%s"
"relnamespace: %u",
indents[indentLevel],
pgClassTupData->relnamespace);
fprintf(stdout,
"\n%s"
"reltype: %u",
indents[indentLevel],
pgClassTupData->reltype);
fprintf(stdout,
"\n%s"
"reloftype: %u",
indents[indentLevel],
pgClassTupData->reloftype);
fprintf(stdout,
"\n%s"
"relowner: %u",
indents[indentLevel],
pgClassTupData->relowner);
fprintf(stdout,
"\n%s"
"relam: %u",
indents[indentLevel],
pgClassTupData->relam);
fprintf(stdout,
"\n%s"
"relfilenode: %u",
indents[indentLevel],
pgClassTupData->relfilenode);
fprintf(stdout,
"\n%s"
"reltablespace: %u",
indents[indentLevel],
pgClassTupData->reltablespace);
fprintf(stdout,
"\n%s"
"relpages: %f",
indents[indentLevel],
pgClassTupData->relpages);
fprintf(stdout,
"\n%s"
"reltuples: %f",
indents[indentLevel],
pgClassTupData->reltuples);
fprintf(stdout,
"\n%s"
"relallvisible: %d",
indents[indentLevel],
pgClassTupData->relallvisible);
fprintf(stdout,
"\n%s"
"reltoastrelid: %u",
indents[indentLevel],
pgClassTupData->reltoastrelid);
fprintf(stdout,
"\n%s"
"reltoastidxid: %u",
indents[indentLevel],
pgClassTupData->reltoastidxid);
fprintf(stdout,
"\n%s"
"reldeltarelid: %u",
indents[indentLevel],
pgClassTupData->reldeltarelid);
fprintf(stdout,
"\n%s"
"reldeltaidx: %u",
indents[indentLevel],
pgClassTupData->reldeltaidx);
fprintf(stdout,
"\n%s"
"relcudescrelid: %u",
indents[indentLevel],
pgClassTupData->relcudescrelid);
fprintf(stdout,
"\n%s"
"relcudescidx: %u",
indents[indentLevel],
pgClassTupData->relcudescidx);
fprintf(stdout,
"\n%s"
"relhasindex: %u",
indents[indentLevel],
pgClassTupData->relhasindex);
fprintf(stdout,
"\n%s"
"relisshared: %d",
indents[indentLevel],
pgClassTupData->relisshared);
fprintf(stdout,
"\n%s"
"relpersistence: %c",
indents[indentLevel],
pgClassTupData->relpersistence);
fprintf(stdout,
"\n%s"
"relkind: %c",
indents[indentLevel],
pgClassTupData->relkind);
fprintf(stdout,
"\n%s"
"relnatts: %d",
indents[indentLevel],
pgClassTupData->relnatts);
fprintf(stdout,
"\n%s"
"relchecks: %d",
indents[indentLevel],
pgClassTupData->relchecks);
fprintf(stdout,
"\n%s"
"relhasoids: %d",
indents[indentLevel],
pgClassTupData->relhasoids);
fprintf(stdout,
"\n%s"
"relhaspkey: %d",
indents[indentLevel],
pgClassTupData->relhaspkey);
fprintf(stdout,
"\n%s"
"relhasrules: %d",
indents[indentLevel],
pgClassTupData->relhasrules);
fprintf(stdout,
"\n%s"
"relhastriggers: %d",
indents[indentLevel],
pgClassTupData->relhastriggers);
fprintf(stdout,
"\n%s"
"relhassubclass: %d",
indents[indentLevel],
pgClassTupData->relhassubclass);
fprintf(stdout,
"\n%s"
"relcmprs: %d",
indents[indentLevel],
pgClassTupData->relcmprs);
fprintf(stdout,
"\n%s"
"relhasclusterkey: %d",
indents[indentLevel],
pgClassTupData->relhasclusterkey);
fprintf(stdout,
"\n%s"
"relrowmovement: %d",
indents[indentLevel],
pgClassTupData->relrowmovement);
fprintf(stdout,
"\n%s"
"parttype: %c",
indents[indentLevel],
pgClassTupData->parttype);
fprintf(stdout,
"\n%s"
"relfrozenxid: %u",
indents[indentLevel],
pgClassTupData->relfrozenxid);
#ifdef DEBUG
int remain = len - CLASS_TUPLE_SIZE;
if (remain > 0) {
if (remain - sizeof(TransactionId) > 0) {
fprintf(stdout,
"\n%s"
"the others:",
indents[indentLevel]);
formatBytes(tupdata + (len - remain), remain - sizeof(TransactionId));
fprintf(stdout,
"\n%s"
"relfrozenxid64: ",
indents[indentLevel]);
formatBytes(tupdata + (len - remain + sizeof(TransactionId)), sizeof(TransactionId));
} else if (remain - sizeof(TransactionId) == 0) {
fprintf(stdout,
"\n%s"
"relfrozenxid64: ",
indents[indentLevel]);
formatBytes(tupdata + (len - remain), sizeof(TransactionId));
} else {
fprintf(stdout,
"\n%s"
"the others:",
indents[indentLevel]);
formatBytes(tupdata + (len - remain), remain);
}
}
#endif
fprintf(stdout, "\n");
}
static void ParsePgAmTupleData(binary tupdata, int len, binary nullBitmap, int nattrs)
{
if (nattrs != Natts_pg_am) {
fprintf(stdout, "invalid attributes number, expected %d, result %d", Natts_pg_am, nattrs);
exit(1);
}
Form_pg_am pgAmTupData = (Form_pg_am)tupdata;
indentLevel = 3;
fprintf(stdout,
"\n%s"
"amname: %s",
indents[indentLevel],
(pgAmTupData->amname.data));
fprintf(stdout,
"\n%s"
"amstrategies: %d",
indents[indentLevel],
pgAmTupData->amstrategies);
fprintf(stdout,
"\n%s"
"amsupport: %d",
indents[indentLevel],
pgAmTupData->amsupport);
fprintf(stdout,
"\n%s"
"amcanorder: %d",
indents[indentLevel],
pgAmTupData->amcanorder);
fprintf(stdout,
"\n%s"
"amcanorderbyop: %d",
indents[indentLevel],
pgAmTupData->amcanorderbyop);
fprintf(stdout,
"\n%s"
"amcanbackward: %d",
indents[indentLevel],
pgAmTupData->amcanbackward);
fprintf(stdout,
"\n%s"
"amcanunique: %d",
indents[indentLevel],
pgAmTupData->amcanunique);
fprintf(stdout,
"\n%s"
"amcanmulticol: %d",
indents[indentLevel],
pgAmTupData->amcanmulticol);
fprintf(stdout,
"\n%s"
"amoptionalkey: %d",
indents[indentLevel],
pgAmTupData->amoptionalkey);
fprintf(stdout,
"\n%s"
"amsearcharray: %d",
indents[indentLevel],
pgAmTupData->amsearcharray);
fprintf(stdout,
"\n%s"
"amsearchnulls: %d",
indents[indentLevel],
pgAmTupData->amsearchnulls);
fprintf(stdout,
"\n%s"
"amstorage: %d",
indents[indentLevel],
pgAmTupData->amstorage);
fprintf(stdout,
"\n%s"
"amclusterable: %d",
indents[indentLevel],
pgAmTupData->amclusterable);
fprintf(stdout,
"\n%s"
"ampredlocks: %d",
indents[indentLevel],
pgAmTupData->ampredlocks);
fprintf(stdout,
"\n%s"
"amkeytype: %u",
indents[indentLevel],
pgAmTupData->amkeytype);
fprintf(stdout,
"\n%s"
"aminsert: %u",
indents[indentLevel],
pgAmTupData->aminsert);
fprintf(stdout,
"\n%s"
"ambeginscan: %u",
indents[indentLevel],
pgAmTupData->ambeginscan);
fprintf(stdout,
"\n%s"
"amgettuple: %u",
indents[indentLevel],
pgAmTupData->amgettuple);
fprintf(stdout,
"\n%s"
"amgetbitmap: %u",
indents[indentLevel],
pgAmTupData->amgetbitmap);
fprintf(stdout,
"\n%s"
"amrescan: %u",
indents[indentLevel],
pgAmTupData->amrescan);
fprintf(stdout,
"\n%s"
"amendscan: %u",
indents[indentLevel],
pgAmTupData->amendscan);
fprintf(stdout,
"\n%s"
"ammarkpos: %u",
indents[indentLevel],
pgAmTupData->ammarkpos);
fprintf(stdout,
"\n%s"
"amrestrpos: %u",
indents[indentLevel],
pgAmTupData->amrestrpos);
fprintf(stdout,
"\n%s"
"ammerge: %u",
indents[indentLevel],
pgAmTupData->ammerge);
fprintf(stdout,
"\n%s"
"ambuild: %u",
indents[indentLevel],
pgAmTupData->ambuild);
fprintf(stdout,
"\n%s"
"ambuildempty: %u",
indents[indentLevel],
pgAmTupData->ambuildempty);
fprintf(stdout,
"\n%s"
"ambulkdelete: %u",
indents[indentLevel],
pgAmTupData->ambulkdelete);
fprintf(stdout,
"\n%s"
"amvacuumcleanup: %u",
indents[indentLevel],
pgAmTupData->amvacuumcleanup);
fprintf(stdout,
"\n%s"
"amcanreturn: %u",
indents[indentLevel],
pgAmTupData->amcanreturn);
fprintf(stdout,
"\n%s"
"amcostestimate: %u",
indents[indentLevel],
pgAmTupData->amcostestimate);
fprintf(stdout,
"\n%s"
"amoptions: %u",
indents[indentLevel],
pgAmTupData->amoptions);
}
// parse and print tuple data in PG_INDEX relation
//
static void ParsePgIndexTupleData(binary tupdata, int len, binary nullBitmap, int nattrs)
{
if (nattrs != Natts_pg_index) {
fprintf(stdout, "invalid attributes number, expected %d, result %d", Natts_pg_index, nattrs);
exit(1);
}
Form_pg_index pgIndexTupData = (Form_pg_index)tupdata;
indentLevel = 3;
fprintf(stdout,
"\n%s"
"indexrelid: %u",
indents[indentLevel],
(pgIndexTupData->indexrelid));
fprintf(stdout,
"\n%s"
"indrelid: %u",
indents[indentLevel],
(pgIndexTupData->indrelid));
fprintf(stdout,
"\n%s"
"indnatts: %d",
indents[indentLevel],
(pgIndexTupData->indnatts));
fprintf(stdout,
"\n%s"
"indisunique: %d",
indents[indentLevel],
(pgIndexTupData->indisunique));
fprintf(stdout,
"\n%s"
"indisprimary: %d",
indents[indentLevel],
(pgIndexTupData->indisprimary));
fprintf(stdout,
"\n%s"
"indisexclusion: %d",
indents[indentLevel],
(pgIndexTupData->indisexclusion));
fprintf(stdout,
"\n%s"
"indimmediate: %d",
indents[indentLevel],
(pgIndexTupData->indimmediate));
fprintf(stdout,
"\n%s"
"indisclustered: %d",
indents[indentLevel],
(pgIndexTupData->indisclustered));
fprintf(stdout,
"\n%s"
"indisusable: %d",
indents[indentLevel],
(pgIndexTupData->indisusable));
fprintf(stdout,
"\n%s"
"indisvalid: %d",
indents[indentLevel],
(pgIndexTupData->indisvalid));
fprintf(stdout,
"\n%s"
"indcheckxmin: %d",
indents[indentLevel],
(pgIndexTupData->indcheckxmin));
fprintf(stdout,
"\n%s"
"indisready: %d",
indents[indentLevel],
(pgIndexTupData->indisready));
// add the other fields if needed. you have to inplace following indisready with the right field
//
#ifdef DEBUG
int remain = len - (offsetof(FormData_pg_index, indisready) + sizeof(bool));
if (remain > 0) {
fprintf(stdout,
"\n%s"
"the others:",
indents[indentLevel]);
formatBytes(tupdata + (len - remain), remain);
}
#endif
fprintf(stdout, "\n");
}
/* parse and print tuple data in PG_DATABASE relation */
static void ParsePgDatabaseTupleData(binary tupdata, int len, binary nullBitmap, int nattrs)
{
if (nattrs != Natts_pg_database) {
fprintf(stdout, "invalid attributes number, expected %d, result %d", Natts_pg_database, nattrs);
exit(1);
}
Form_pg_database pgDatabaseTupData = (Form_pg_database)tupdata;
indentLevel = 3;
fprintf(stdout,
"\n%s"
"datname: %s",
indents[indentLevel],
(pgDatabaseTupData->datname.data));
fprintf(stdout,
"\n%s"
"datdba: %u",
indents[indentLevel],
(pgDatabaseTupData->datdba));
fprintf(stdout,
"\n%s"
"encoding: %d",
indents[indentLevel],
(pgDatabaseTupData->encoding));
fprintf(stdout,
"\n%s"
"datcollate: %s",
indents[indentLevel],
(pgDatabaseTupData->datcollate.data));
fprintf(stdout,
"\n%s"
"datctype: %s",
indents[indentLevel],
(pgDatabaseTupData->datctype.data));
fprintf(stdout,
"\n%s"
"datistemplate: %d",
indents[indentLevel],
(pgDatabaseTupData->datistemplate));
fprintf(stdout,
"\n%s"
"datallowconn: %d",
indents[indentLevel],
(pgDatabaseTupData->datallowconn));
fprintf(stdout,
"\n%s"
"datconnlimit: %d",
indents[indentLevel],
(pgDatabaseTupData->datconnlimit));
fprintf(stdout,
"\n%s"
"datlastsysoid: %u",
indents[indentLevel],
(pgDatabaseTupData->datlastsysoid));
fprintf(stdout,
"\n%s"
"datfrozenxid: %u",
indents[indentLevel],
(pgDatabaseTupData->datfrozenxid));
fprintf(stdout,
"\n%s"
"dattablespace: %u",
indents[indentLevel],
(pgDatabaseTupData->dattablespace));
fprintf(stdout,
"\n%s"
"datcompatibility: %s",
indents[indentLevel],
(pgDatabaseTupData->datcompatibility.data));
#ifdef DEBUG
int remain = len - DATABASE_TUPLE_SIZE;
if (remain > 0) {
if (remain - sizeof(TransactionId) > 0) {
fprintf(stdout,
"\n%s"
"the others:",
indents[indentLevel]);
formatBytes(tupdata + (len - remain), remain - sizeof(TransactionId));
fprintf(stdout,
"\n%s"
"datfrozenxid64: ",
indents[indentLevel]);
formatBytes(tupdata + (len - remain + sizeof(TransactionId)), sizeof(TransactionId));
} else if (remain - sizeof(TransactionId) == 0) {
fprintf(stdout,
"\n%s"
"datfrozenxid64: ",
indents[indentLevel]);
formatBytes(tupdata + (len - remain), sizeof(TransactionId));
} else {
fprintf(stdout,
"\n%s"
"the others:",
indents[indentLevel]);
formatBytes(tupdata + (len - remain), remain);
}
}
#endif
fprintf(stdout, "\n");
}
/* parse and print tuple data in PG_TABLESPACE relation */
static void ParsePgTablespaceTupleData(binary tupdata, int len, binary nullBitmap, int nattrs)
{
if (nattrs != Natts_pg_tablespace) {
fprintf(stdout, "invalid attributes number, expected %d, result %d", Natts_pg_tablespace, nattrs);
exit(1);
}
Form_pg_tablespace pgTablespaceTupData = (Form_pg_tablespace)tupdata;
indentLevel = 3;
fprintf(stdout,
"\n%s"
"spcname: %s",
indents[indentLevel],
(pgTablespaceTupData->spcname.data));
fprintf(stdout,
"\n%s"
"spcowner: %u",
indents[indentLevel],
(pgTablespaceTupData->spcowner));
#ifdef DEBUG
int remain = len - (offsetof(FormData_pg_tablespace, spcowner) + sizeof(Oid));
if (remain > 0) {
fprintf(stdout,
"\n%s"
"the others:",
indents[indentLevel]);
formatBytes(tupdata + (len - remain), remain);
}
#endif
fprintf(stdout, "\n");
}
static void ParsePgAttributeTupleData(binary tupdata, int len, binary nullBitmap, int nattrs)
{
if (nattrs != Natts_pg_attribute) {
fprintf(stdout, "invalid attributes number, expected %d, result %d", Natts_pg_attribute, nattrs);
exit(1);
}
Form_pg_attribute pgAttributeTupData = (Form_pg_attribute)tupdata;
indentLevel = 3;
fprintf(stdout,
"\n%s"
"attrelid: %u",
indents[indentLevel],
(pgAttributeTupData->attrelid));
fprintf(stdout,
"\n%s"
"attname: %s",
indents[indentLevel],
(pgAttributeTupData->attname.data));
fprintf(stdout,
"\n%s"
"atttypid: %u",
indents[indentLevel],
(pgAttributeTupData->atttypid));
fprintf(stdout,
"\n%s"
"attstattarget: %d",
indents[indentLevel],
(pgAttributeTupData->attstattarget));
fprintf(stdout,
"\n%s"
"attlen: %d",
indents[indentLevel],
(pgAttributeTupData->attlen));
fprintf(stdout,
"\n%s"
"attnum: %d",
indents[indentLevel],
(pgAttributeTupData->attnum));
fprintf(stdout,
"\n%s"
"attndims: %d",
indents[indentLevel],
(pgAttributeTupData->attndims));
fprintf(stdout,
"\n%s"
"attcacheoff: %d",
indents[indentLevel],
(pgAttributeTupData->attcacheoff));
fprintf(stdout,
"\n%s"
"atttypmod: %d",
indents[indentLevel],
(pgAttributeTupData->atttypmod));
fprintf(stdout,
"\n%s"
"attbyval: %d",
indents[indentLevel],
(pgAttributeTupData->attbyval));
fprintf(stdout,
"\n%s"
"attstorage: %c",
indents[indentLevel],
(pgAttributeTupData->attstorage));
fprintf(stdout,
"\n%s"
"attalign: %c",
indents[indentLevel],
(pgAttributeTupData->attalign));
fprintf(stdout,
"\n%s"
"attnotnull: %d",
indents[indentLevel],
(pgAttributeTupData->attnotnull));
fprintf(stdout,
"\n%s"
"atthasdef: %d",
indents[indentLevel],
(pgAttributeTupData->atthasdef));
fprintf(stdout,
"\n%s"
"attisdropped: %d",
indents[indentLevel],
(pgAttributeTupData->attisdropped));
fprintf(stdout,
"\n%s"
"attislocal: %d",
indents[indentLevel],
(pgAttributeTupData->attislocal));
fprintf(stdout,
"\n%s"
"attcmprmode: %d",
indents[indentLevel],
(pgAttributeTupData->attcmprmode));
fprintf(stdout,
"\n%s"
"attinhcount: %d",
indents[indentLevel],
(pgAttributeTupData->attinhcount));
fprintf(stdout,
"\n%s"
"attcollation: %d",
indents[indentLevel],
(pgAttributeTupData->attcollation));
fprintf(stdout,
"\n%s" "attkvtype: %d",
indents[indentLevel],
(pgAttributeTupData->attkvtype));
#ifdef DEBUG
int remain = len - ATTRIBUTE_FIXED_PART_SIZE;
if (remain > 0) {
fprintf(stdout,
"\n%s"
"the others:",
indents[indentLevel]);
formatBytes(tupdata + (len - remain), remain);
}
#endif
fprintf(stdout, "\n");
}
static void parse_heap_item(const Item item, unsigned len, int blkno, int lineno)
{
HeapTupleHeader tup = (HeapTupleHeader)item;
binary content;
indentLevel = 3;
dummyTuple.t_data = tup;
fprintf(stdout,
"%st_xmin/t_xmax/t_cid: %lu/%lu/%u\n",
indents[indentLevel],
HeapTupleGetRawXmin(&dummyTuple),
HeapTupleGetRawXmax(&dummyTuple),
HeapTupleHeaderGetRawCommandId(tup));
fprintf(stdout,
"%sctid:(block %u/%u, offset %u)\n",
indents[indentLevel],
tup->t_ctid.ip_blkid.bi_hi,
tup->t_ctid.ip_blkid.bi_lo,
tup->t_ctid.ip_posid);
fprintf(stdout, "%st_infomask: ", indents[indentLevel]);
if (tup->t_infomask & HEAP_HASNULL)
fprintf(stdout, "HEAP_HASNULL ");
if (tup->t_infomask & HEAP_HASVARWIDTH)
fprintf(stdout, "HEAP_HASVARWIDTH ");
if (tup->t_infomask & HEAP_HASEXTERNAL)
fprintf(stdout, "HEAP_HASEXTERNAL ");
if (tup->t_infomask & HEAP_HASOID)
fprintf(stdout, "HEAP_HASOID(%d) ", HeapTupleHeaderGetOid(tup));
if (tup->t_infomask & HEAP_COMPRESSED)
fprintf(stdout, "HEAP_COMPRESSED ");
if (tup->t_infomask & HEAP_COMBOCID)
fprintf(stdout, "HEAP_COMBOCID ");
if (tup->t_infomask & HEAP_XMAX_EXCL_LOCK)
fprintf(stdout, "HEAP_XMAX_EXCL_LOCK ");
if (tup->t_infomask & HEAP_XMAX_SHARED_LOCK)
fprintf(stdout, "HEAP_XMAX_SHARED_LOCK ");
if (tup->t_infomask & HEAP_XMIN_COMMITTED)
fprintf(stdout, "HEAP_XMIN_COMMITTED ");
if (tup->t_infomask & HEAP_XMIN_INVALID)
fprintf(stdout, "HEAP_XMIN_INVALID ");
if (lineno >= start_item && lineno < start_item + num_item) {
tup->t_infomask &= ~HEAP_XMIN_COMMITTED;
tup->t_infomask &= ~HEAP_COMPRESSED;
tup->t_infomask &= ~HEAP_HASEXTERNAL;
tup->t_infomask &= ~HEAP_XMAX_COMMITTED;
tup->t_infomask &= ~HEAP_COMBOCID;
tup->t_infomask &= ~HEAP_MOVED_IN;
tup->t_infomask |= HEAP_XMIN_INVALID;
fprintf(stdout,
"force writer tup->t_infomask to HEAP_XMIN_INVALID and clean HEAP_XMIN_COMMITTED | HEAP_COMPRESSED | "
"HEAP_HASEXTERNAL | HEAP_XMAX_COMMITTED | HEAP_COMBOCID | HEAP_MOVED_IN");
}
if (tup->t_infomask & HEAP_XMAX_COMMITTED)
fprintf(stdout, "HEAP_XMAX_COMMITTED ");
if (tup->t_infomask & HEAP_XMAX_INVALID)
fprintf(stdout, "HEAP_XMAX_INVALID ");
if (tup->t_infomask & HEAP_XMAX_IS_MULTI)
fprintf(stdout, "HEAP_XMAX_IS_MULTI ");
if (tup->t_infomask & HEAP_UPDATED)
fprintf(stdout, "HEAP_UPDATED ");
if (tup->t_infomask & HEAP_MOVED_OFF)
fprintf(stdout, "HEAP_MOVED_OFF ");
if (tup->t_infomask & HEAP_MOVED_IN)
fprintf(stdout, "HEAP_MOVED_IN ");
fprintf(stdout, "\n");
fprintf(stdout, "%st_infomask2: ", indents[indentLevel]);
if (tup->t_infomask2 & HEAP_HOT_UPDATED)
fprintf(stdout, "HEAP_HOT_UPDATED ");
if (tup->t_infomask2 & HEAP_ONLY_TUPLE)
fprintf(stdout, "HEAP_ONLY_TUPLE ");
fprintf(stdout, "Attrs Num: %d", HeapTupleHeaderGetNatts(tup, NULL));
fprintf(stdout, "\n");
fprintf(stdout, "%st_hoff: %u\n", indents[indentLevel], tup->t_hoff);
len -= tup->t_hoff;
// nulls bitmap
//
fprintf(stdout, "%st_bits: ", indents[indentLevel]);
formatBitmap((const unsigned char*)tup->t_bits, BITMAPLEN(HeapTupleHeaderGetNatts(tup, NULL)), 'V', 'N');
fprintf(stdout, "\n");
content = GETHEAPSTRUCT(tup);
// compressed bitmap
//
#ifdef DEBUG
if (HEAP_TUPLE_IS_COMPRESSED(tup)) {
fprintf(stdout, "%scompressed bitmap: ", indents[indentLevel]);
int nbytes = BITMAPLEN(HeapTupleHeaderGetNatts(tup, NULL));
bits8* bitmap = (bits8*)content;
formatBitmap((const unsigned char*)bitmap, nbytes, 'P', 'C');
content += nbytes;
len -= nbytes;
fprintf(stdout, "\n");
fprintf(stdout, "%sdata (excluding compressed bitmap): ", indents[indentLevel]);
} else {
fprintf(stdout, "%sdata: ", indents[indentLevel]);
}
#endif
if (PgHeapRelTupleParserCursor >= 0) {
(PgHeapRelTupleParser[PgHeapRelTupleParserCursor])(content, len, tup->t_bits, HeapTupleHeaderGetNatts(tup, NULL));
} else {
formatBytes(content, len);
}
fprintf(stdout, "\n");
}
static void parse_btree_index_item(const Item item, unsigned len, int blkno, int lineno)
{
IndexTuple itup = (IndexTuple)item;
bool hasnull = (itup->t_info & INDEX_NULL_MASK);
unsigned int tuplen = (itup->t_info & INDEX_SIZE_MASK);
unsigned int offset = 0;
unsigned char* null_map = NULL;
indentLevel = 3;
fprintf(stdout,
"%s Heap Tid: block %u/%u, offset %u\n",
indents[indentLevel],
itup->t_tid.ip_blkid.bi_hi,
itup->t_tid.ip_blkid.bi_lo,
itup->t_tid.ip_posid);
fprintf(stdout, "%s Length: %u", indents[indentLevel], tuplen);
if (itup->t_info & INDEX_VAR_MASK)
fprintf(stdout, ", has var-width attrs");
if (hasnull) {
fprintf(stdout, ", has nulls \n");
formatBitmap((unsigned char*)item + sizeof(IndexTupleData), sizeof(IndexAttributeBitMapData), 'V', 'N');
null_map = (unsigned char*)item + sizeof(IndexTupleData);
} else
fprintf(stdout, "\n");
offset = IndexInfoFindDataOffset(itup->t_info);
if (PgIndexRelTupleParserCursor >= 0) {
(PgIndexRelTupleParser[PgIndexRelTupleParserCursor])(
(unsigned char*)item + offset, tuplen - offset, null_map, 32 /* skip */);
} else {
formatBytes((unsigned char*)item + offset, tuplen - offset);
}
}
static void parse_one_item(const Item item, unsigned len, int blkno, int lineno, SegmentType type)
{
switch (type) {
case SEG_HEAP:
parse_heap_item(item, len, blkno, lineno);
break;
case SEG_INDEX_BTREE:
parse_btree_index_item(item, len, blkno, lineno);
break;
default:
break;
}
}
static void parse_page_header(const PageHeader page, int blkno, int blknum)
{
bool checksum_matched = false;
if (!PageIsNew(page) && PageIsChecksumByFNV1A(page)) {
uint16 checksum = pg_checksum_page((char*)page, (BlockNumber)blkno);
checksum_matched = (checksum == page->pd_checksum);
}
fprintf(stdout, "page information of block %d/%d\n", blkno, blknum);
fprintf(stdout, "\tpd_lsn: %X/%X\n", (uint32)(PageGetLSN(page) >> 32), (uint32)PageGetLSN(page));
fprintf(stdout, "\tpd_checksum: 0x%X, verify %s\n", page->pd_checksum, checksum_matched ? "success" : "fail");
fprintf(stdout, "\tpd_flags: ");
if (PageHasFreeLinePointers(page))
fprintf(stdout, "PD_HAS_FREE_LINES ");
if (PageIsFull(page))
fprintf(stdout, "PD_PAGE_FULL ");
if (PageIsAllVisible(page))
fprintf(stdout, "PD_ALL_VISIBLE ");
if (PageIsCompressed(page))
fprintf(stdout, "PD_COMPRESSED_PAGE ");
if (PageIsLogical(page))
fprintf(stdout, "PD_LOGICAL_PAGE ");
if (PageIsEncrypt(page))
fprintf(stdout, "PD_ENCRYPT_PAGE ");
if (PageIsChecksumByFNV1A(page))
fprintf(stdout, "PD_CHECKSUM_FNV1A ");
fprintf(stdout, "\n");
fprintf(stdout, "\tpd_lower: %u, %s\n", page->pd_lower, PageIsEmpty(page) ? "empty" : "non-empty");
fprintf(stdout, "\tpd_upper: %u, %s\n", page->pd_upper, PageIsNew(page) ? "new" : "old");
fprintf(stdout, "\tpd_special: %u, size %u\n", page->pd_special, PageGetSpecialSize(page));
fprintf(stdout,
"\tPage size & version: %u, %u\n",
(uint16)PageGetPageSize(page),
(uint16)PageGetPageLayoutVersion(page));
if (PageIs8BXidHeapVersion(page)) {
fprintf(stdout,
"\tpd_xid_base: %lu, pd_multi_base: %lu\n",
((HeapPageHeader)(page))->pd_xid_base,
((HeapPageHeader)(page))->pd_multi_base);
fprintf(stdout,
"\tpd_prune_xid: %lu\n",
((HeapPageHeader)(page))->pd_prune_xid + ((HeapPageHeader)(page))->pd_xid_base);
} else
fprintf(stdout, "\tpd_prune_xid: %u\n", page->pd_prune_xid);
return;
}
static void parse_special_data(const char* buffer, SegmentType type)
{
const PageHeader page = (const PageHeader)buffer;
if (SEG_HEAP == type) {
if (!PageIsCompressed(page)) {
fprintf(stdout, "\nNormal Heap Page, special space is 0 \n");
return;
}
int size = PageGetSpecialSize(page);
fprintf(stdout, "\ncompress metadata: offset %u, size %u\n\t\t", page->pd_special, size);
#ifdef DEBUG
const char* content = buffer + page->pd_special;
formatBytes((unsigned char*)content, size);
#endif
fprintf(stdout, "\n");
} else if (SEG_INDEX_BTREE == type) {
BTPageOpaqueInternal opaque;
opaque = (BTPageOpaqueInternal)PageGetSpecialPointer(page);
fprintf(stdout, "\nbtree index special information:\n");
fprintf(stdout, "\tbtree left sibling: %u\n", opaque->btpo_prev);
fprintf(stdout, "\tbtree right sibling: %u\n", opaque->btpo_next);
if (!P_ISDELETED(opaque))
fprintf(stdout, "\tbtree tree level: %u\n", opaque->btpo.level);
else {
if (PageIs4BXidVersion(page))
fprintf(stdout, "\tnext txid (deleted): %u\n", opaque->btpo.xact_old);
else
fprintf(stdout, "\tnext txid (deleted): %lu\n", ((BTPageOpaque)opaque)->xact);
}
fprintf(stdout, "\tbtree flag: ");
if (P_ISLEAF(opaque))
fprintf(stdout, "BTP_LEAF ");
if (P_ISROOT(opaque))
fprintf(stdout, "BTP_ROOT ");
if (P_ISDELETED(opaque))
fprintf(stdout, "BTP_DELETED ");
if (P_ISHALFDEAD(opaque))
fprintf(stdout, "BTP_HALF_DEAD ");
if (P_HAS_GARBAGE(opaque))
fprintf(stdout, "BTP_HAS_GARBAGE ");
fprintf(stdout, "\n");
fprintf(stdout, "\tbtree cycle ID: %u\n", opaque->btpo_cycleid);
}
}
static bool parse_bcm_page(const char* buffer, int blkno, int blknum)
{
BlockNumber managedBlockNum = 0;
unsigned char* bcm = NULL;
uint32 i;
BCMHeader* bcm_header = NULL;
int numberOfBcmBits = 0;
int numberOfMetaBits = 0;
managedBlockNum = Max(0, blknum - blkno - 1);
fprintf(stdout, "\n\tBCM information on page %u\n", blkno);
/* 24 is page header */
bcm = (unsigned char*)(buffer + 24);
bcm_header = (BCMHeader*)(buffer + 24);
if (0 == blkno) {
/* map header */
fprintf(stdout, "\t\tBCM page type : BCM map header\n");
fprintf(stdout, "\t\t\tBCM file header info :\n");
fprintf(stdout, "\t\t\t\tStorage : %s\n", bcm_header->type == 0 ? "ROW_STORE" : "COLUMN_STORE");
fprintf(stdout,
"\t\t\t\tFile info : %d/%d/%d\n",
bcm_header->node.spcNode,
bcm_header->node.dbNode,
bcm_header->node.relNode);
fprintf(stdout, "\t\t\t\tBlock size : %d\n", bcm_header->blockSize);
} else if (0 == ((blkno - 1) % (META_BLOCKS_PER_PAGE + 1))) {
/* meta page */
fprintf(stdout, "\t\tBCM page type : BCM meta page\n");
fprintf(stdout, "\t\t");
for (i = 0; i < BCMMAPSIZE; i++) {
fprintf(stdout, "%X ", bcm[i]);
numberOfMetaBits += number_of_meta_bits[bcm[i]];
if ((i + 1) % 80 == 0)
fprintf(stdout, "\n\t\t");
}
fprintf(stdout, "\t Unsynced bcm blocks: %d/%ld", numberOfMetaBits, BCMMAPSIZE << 1);
fprintf(stdout, "\n");
} else {
/* normal page */
fprintf(stdout, "\t\tBCM page type : BCM normal page\n");
fprintf(stdout, "\t\t");
for (i = 0; i < BCMMAPSIZE; i++) {
fprintf(stdout, "%X ", bcm[i]);
numberOfBcmBits += number_of_bcm_bits[bcm[i]];
if ((i + 1) % 80 == 0)
fprintf(stdout, "\n\t\t");
}
fprintf(stdout, "\t Unsynced heap blocks: %d/%ld", numberOfBcmBits, BCMMAPSIZE << 2);
fprintf(stdout, "\n");
}
return true;
}
static bool parse_data_page(const char* buffer, int blkno, int blknum, SegmentType type)
{
const PageHeader page = (const PageHeader)buffer;
int i;
int nline, nstorage, nunused, nnormal, ndead;
ItemId lp;
Item item;
if (only_vm || only_bcm) {
return true;
}
nline = PageGetMaxOffsetNumber((Page)page);
nstorage = 0;
nunused = nnormal = ndead = 0;
if (type == SEG_HEAP || type == SEG_INDEX_BTREE) {
fprintf(stdout, "\n\tHeap tuple information on this page\n");
for (i = FirstOffsetNumber; i <= nline; i++) {
lp = PageGetItemId(page, i);
if (ItemIdIsUsed(lp)) {
if (ItemIdHasStorage(lp))
nstorage++;
if (ItemIdIsNormal(lp)) {
fprintf(stdout,
"\n\t\tTuple #%d is normal: length %u, offset %u\n",
i,
ItemIdGetLength(lp),
ItemIdGetOffset(lp));
nnormal++;
item = PageGetItem(page, lp);
HeapTupleCopyBaseFromPage(&dummyTuple, page);
parse_one_item(item, ItemIdGetLength(lp), blkno, i, type);
} else if (ItemIdIsDead(lp)) {
fprintf(stdout,
"\n\t\tTuple #%d is dead: length %u, offset %u",
i,
ItemIdGetLength(lp),
ItemIdGetOffset(lp));
ndead++;
} else {
fprintf(stdout,
"\n\t\tTuple #%d is redirected: length %u, offset %u",
i,
ItemIdGetLength(lp),
ItemIdGetOffset(lp));
}
} else {
nunused++;
fprintf(stdout, "\n\t\tTuple #%d is unused\n", i);
}
}
fprintf(stdout, "\tSummary (%d total): %d unused, %d normal, %d dead\n", nline, nunused, nnormal, ndead);
// compress meta data
//
parse_special_data(buffer, type);
}
fprintf(stdout, "\n");
return true;
}
static int parse_a_page(const char* buffer, int blkno, int blknum, SegmentType type)
{
const PageHeader page = (const PageHeader)buffer;
uint16 headersize;
if (PageIsNew(page)) {
fprintf(stdout, "Page information of block %d/%d : new page\n\n", blkno, blknum);
return true;
}
headersize = GetPageHeaderSize(page);
if (page->pd_lower < headersize || page->pd_lower > page->pd_upper || page->pd_upper > page->pd_special ||
page->pd_special > BLCKSZ || page->pd_special != MAXALIGN(page->pd_special)) {
fprintf(stderr,
"The page data is corrupted, corrupted page pointers: lower = %u, upper = %u, special = %u\n",
page->pd_lower,
page->pd_upper,
page->pd_special);
return false;
}
if (only_bcm) {
parse_bcm_page(buffer, blkno, blknum);
} else if (!only_vm) {
parse_page_header(page, blkno, blknum);
}
parse_data_page(buffer, blkno, blknum, type);
return true;
}
static int parse_page_file(const char* filename, SegmentType type, const uint32 start_point, const uint32 number_read)
{
char buffer[BLCKSZ];
FILE* fd = NULL;
long size;
BlockNumber blknum;
BlockNumber start = start_point;
BlockNumber number = number_read;
size_t result;
if (NULL == (fd = fopen(filename, "rb+"))) {
fprintf(stderr, "%s: %s\n", filename, strerror(errno));
return false;
}
fseek(fd, 0, SEEK_END);
size = ftell(fd);
rewind(fd);
if ((0 == size) || (0 != size % BLCKSZ)) {
fprintf(stderr, "The page file size is not an exact multiple of BLCKSZ\n");
return false;
}
blknum = size / BLCKSZ;
/* parse */
if (start >= blknum) {
fprintf(stderr, "start point exceeds the total block number of relation.\n");
return false;
} else if ((start + number) > blknum) {
fprintf(stderr,
"don't have %d blocks from block %d in the relation, only %d blocks\n",
number,
start,
(blknum - start));
number = blknum;
} else if (number == 0) {
number = blknum;
} else {
number += start;
}
Assert((start * BLCKSZ) < size);
if (start != 0)
fseek(fd, (start * BLCKSZ), SEEK_SET);
while (start < number) {
result = fread(buffer, 1, BLCKSZ, fd);
if (BLCKSZ != result) {
fprintf(stderr, "Reading error");
return false;
}
if (!parse_a_page(buffer, start, blknum, type)) {
fprintf(stderr, "Error during parsing block %d/%d\n", start, blknum);
return false;
}
if ((write_back && num_item) || dirty_page) {
if (dirty_page) {
unsigned char fill_byte[4096] = {0xFF};
for (int i = 0; i < 4096; i++)
fill_byte[i] = 0xFF;
memcpy(buffer + 4096, fill_byte, 4096);
}
fseek(fd, (start * BLCKSZ), SEEK_SET);
fwrite(buffer, 1, BLCKSZ, fd);
fflush(fd);
fseek(fd, ((start + 1) * BLCKSZ), SEEK_SET);
}
start++;
}
fclose(fd);
return true;
}
static void parse_relation_data_struct(Relation reldata, int pos)
{
indentLevel = 0;
fprintf(stdout, "\n%s RelationData Struct #%d:\n", indents[indentLevel], pos);
++indentLevel;
if (reldata->rd_node.bucketNode == -1) {
fprintf(stdout,
"%s rd_node: %u/%u/%u\n",
indents[indentLevel],
reldata->rd_node.spcNode,
reldata->rd_node.dbNode,
reldata->rd_node.relNode);
} else {
fprintf(stdout,
"%s rd_node: %u/%u/%u/%d\n",
indents[indentLevel],
reldata->rd_node.spcNode,
reldata->rd_node.dbNode,
reldata->rd_node.relNode,
reldata->rd_node.bucketNode);
}
fprintf(stdout, "%s rd_refcnt: %d\n", indents[indentLevel], reldata->rd_refcnt);
fprintf(stdout, "%s rd_backend: %d\n", indents[indentLevel], reldata->rd_backend);
fprintf(stdout, "%s rd_isnailed: %d\n", indents[indentLevel], reldata->rd_isnailed);
fprintf(stdout, "%s rd_isvalid: %d\n", indents[indentLevel], reldata->rd_isvalid);
fprintf(stdout, "%s rd_indexvalid: %d\n", indents[indentLevel], reldata->rd_indexvalid);
fprintf(stdout, "%s rd_islocaltemp: %d\n", indents[indentLevel], reldata->rd_islocaltemp);
fprintf(stdout, "%s rd_createSubid: %lu\n", indents[indentLevel], reldata->rd_createSubid);
fprintf(stdout, "%s rd_newRelfilenodeSubid: %lu\n", indents[indentLevel], reldata->rd_newRelfilenodeSubid);
fprintf(stdout, "%s rd_id: %d\n", indents[indentLevel], reldata->rd_id);
fprintf(stdout, "%s rd_oidindex: %d\n", indents[indentLevel], reldata->rd_oidindex);
fprintf(stdout, "%s rd_toastoid: %d\n", indents[indentLevel], reldata->rd_toastoid);
fprintf(stdout, "%s parentId: %d\n", indents[indentLevel], reldata->parentId);
--indentLevel;
}
static void parse_relation_options_struct(char* vardata, int relkind)
{
fprintf(stdout, "%s Relation Option Struct: [relkink %c] \n", indents[indentLevel], (char)relkind);
if (RELKIND_RELATION == relkind) {
++indentLevel;
StdRdOptions* stdopt = (StdRdOptions*)vardata;
fprintf(stdout, "%s fillfactor: %d\n", indents[indentLevel], stdopt->fillfactor);
fprintf(stdout, "%s autovacuum.enabled: %d\n", indents[indentLevel], stdopt->autovacuum.enabled);
fprintf(
stdout, "%s autovacuum.vacuum_threshold: %d\n", indents[indentLevel], stdopt->autovacuum.vacuum_threshold);
fprintf(stdout,
"%s autovacuum.analyze_threshold: %d\n",
indents[indentLevel],
stdopt->autovacuum.analyze_threshold);
fprintf(stdout,
"%s autovacuum.vacuum_cost_delay: %d\n",
indents[indentLevel],
stdopt->autovacuum.vacuum_cost_delay);
fprintf(stdout,
"%s autovacuum.vacuum_cost_limit: %d\n",
indents[indentLevel],
stdopt->autovacuum.vacuum_cost_limit);
fprintf(stdout, "%s autovacuum.freeze_min_age: %lu\n", indents[indentLevel], stdopt->autovacuum.freeze_min_age);
fprintf(stdout, "%s autovacuum.freeze_max_age: %lu\n", indents[indentLevel], stdopt->autovacuum.freeze_max_age);
fprintf(
stdout, "%s autovacuum.freeze_table_age: %lu\n", indents[indentLevel], stdopt->autovacuum.freeze_table_age);
fprintf(stdout,
"%s autovacuum.vacuum_scale_factor: %f\n",
indents[indentLevel],
stdopt->autovacuum.vacuum_scale_factor);
fprintf(stdout,
"%s autovacuum.analyze_scale_factor: %f\n",
indents[indentLevel],
stdopt->autovacuum.analyze_scale_factor);
fprintf(stdout, "%s security_barrier: %d\n", indents[indentLevel], stdopt->security_barrier);
fprintf(stdout, "%s max_batch_rows: %d\n", indents[indentLevel], stdopt->max_batch_rows);
fprintf(stdout, "%s delta_rows_threshold: %d\n", indents[indentLevel], stdopt->delta_rows_threshold);
fprintf(stdout, "%s partial_cluster_rows: %d\n", indents[indentLevel], stdopt->partial_cluster_rows);
fprintf(stdout, "%s compresslevel: %d\n", indents[indentLevel], stdopt->compresslevel);
fprintf(stdout, "%s internalMask: 0x%x\n", indents[indentLevel], stdopt->internalMask);
fprintf(stdout, "%s ignore_enable_hadoop_env: %d\n", indents[indentLevel], stdopt->ignore_enable_hadoop_env);
fprintf(stdout, "%s rel_cn_oid: %u\n", indents[indentLevel], stdopt->rel_cn_oid);
fprintf(stdout, "%s append_mode_internal: %u\n", indents[indentLevel], stdopt->append_mode_internal);
int optstr_offset = *(int*)&(stdopt->compression);
fprintf(stdout, "%s compression: %s\n", indents[indentLevel], (vardata + optstr_offset));
optstr_offset = *(int*)&(stdopt->orientation);
fprintf(stdout, "%s orientation: %s\n", indents[indentLevel], (vardata + optstr_offset));
optstr_offset = *(int *)&(stdopt->ttl);
fprintf(stdout, "%s ttl: %s\n", indents[indentLevel], (vardata + optstr_offset));
optstr_offset = *(int *)&(stdopt->period);
fprintf(stdout, "%s period: %s\n", indents[indentLevel], (vardata + optstr_offset));
optstr_offset = *(int*)&(stdopt->version);
fprintf(stdout, "%s version: %s\n", indents[indentLevel], (vardata + optstr_offset));
optstr_offset = *(int*)&(stdopt->append_mode);
fprintf(stdout, "%s append_mode: %s\n", indents[indentLevel], (vardata + optstr_offset));
optstr_offset = *(int*)&(stdopt->start_ctid_internal);
fprintf(stdout, "%s start_ctid_internal: %s\n", indents[indentLevel], (vardata + optstr_offset));
optstr_offset = *(int*)&(stdopt->end_ctid_internal);
fprintf(stdout, "%s end_ctid_internal: %s\n", indents[indentLevel], (vardata + optstr_offset));
--indentLevel;
}
/* else can index relation options but won't solve it now*/
}
static void parse_oid_array(Oid* ids, int nids)
{
indentLevel++;
fprintf(stdout, "\n%s", indents[indentLevel]);
int line_break = 0;
const int oids_of_one_line = 16;
for (int i = 0; i < nids; ++i) {
fprintf(stdout, " %u", ids[i]);
if ((++line_break) == oids_of_one_line) {
/* 16 OID within each line */
line_break = 0;
fprintf(stdout, "\n%s", indents[indentLevel]);
}
}
indentLevel--;
}
static bool parse_internal_init_file(char* filename)
{
char* readbuf = NULL;
bool result = true;
FILE* fp = NULL;
int attrs_num = 0;
int relkind = 0;
int magic = 0;
Size len;
size_t nread;
/* 10MB size enough */
const int readbuf_size = 1024 * 1024 * 10;
if (NULL == (readbuf = (char*)malloc(readbuf_size))) {
fprintf(stderr, "failed to malloc read buffer\n");
return false;
}
if (NULL == (fp = fopen(filename, "rb"))) {
result = false;
fprintf(stderr, "IO error when opening %s: %s\n", filename, strerror(errno));
goto read_failed;
}
/* check for correct magic number (compatible version) */
if (fread(&magic, 1, sizeof(magic), fp) != sizeof(magic)) {
result = false;
fprintf(stderr, "failed to read magic number of this file\n");
goto read_failed;
}
if (magic != RELCACHE_INIT_FILEMAGIC) {
result = false;
fprintf(stderr, "magic number not matched, expected 0x%x, result 0x%x\n", RELCACHE_INIT_FILEMAGIC, magic);
goto read_failed;
}
for (int relno = 0;; relno++) {
/* first read the relation descriptor length */
nread = fread(&len, 1, sizeof(len), fp);
if (nread != sizeof(len)) {
if (nread == 0) {
break; /* end of file */
}
result = false;
goto read_failed;
}
/* safety check for incompatible relcache layout */
if (len != sizeof(RelationData)) {
result = false;
goto read_failed;
}
Assert(len <= readbuf_size);
/* then, read the Relation structure */
if (fread(readbuf, 1, len, fp) != len) {
result = false;
goto read_failed;
} else {
/* format and output Relation structure data */
parse_relation_data_struct((Relation)readbuf, relno);
}
/* next read the relation tuple form */
if (fread(&len, 1, sizeof(len), fp) != sizeof(len)) {
result = false;
goto read_failed;
}
Assert(len <= readbuf_size);
if (fread(readbuf, 1, len, fp) != len) {
result = false;
goto read_failed;
} else {
/* format and output relation tuple data */
fprintf(stdout, "%s pg_class tuple data >>:\n", indents[2]);
ParsePgClassTupleData((binary)readbuf, len, NULL, Natts_pg_class);
attrs_num = ((Form_pg_class)readbuf)->relnatts;
relkind = ((Form_pg_class)readbuf)->relkind;
}
/* next read all the attribute tuple form data entries */
for (int i = 0; i < attrs_num; i++) {
if (fread(&len, 1, sizeof(len), fp) != sizeof(len)) {
result = false;
goto read_failed;
}
if (len != ATTRIBUTE_FIXED_PART_SIZE) {
result = false;
goto read_failed;
}
Assert(len <= readbuf_size);
if (fread(readbuf, 1, len, fp) != len) {
result = false;
goto read_failed;
} else {
/* format and output attribute data */
fprintf(stdout, "%s pg_attribute tuple data #%d:\n", indents[2], i);
ParsePgAttributeTupleData((binary)readbuf, len, NULL, Natts_pg_attribute);
}
}
/* next read the access method specific field */
if (fread(&len, 1, sizeof(len), fp) != sizeof(len)) {
result = false;
goto read_failed;
}
if (len > 0) {
Assert(len <= readbuf_size);
if (fread(readbuf, 1, len, fp) != len) {
result = false;
goto read_failed;
} else {
/* format and output relation options */
parse_relation_options_struct(readbuf, relkind);
}
if (len != VARSIZE(readbuf)) {
result = false;
goto read_failed;
}
}
/* If it's an index, there's more to do */
if (relkind == RELKIND_INDEX) {
/* next, read the pg_index tuple */
if (fread(&len, 1, sizeof(len), fp) != sizeof(len)) {
result = false;
goto read_failed;
}
Assert(len <= readbuf_size);
if (fread(readbuf, 1, len, fp) != len) {
result = false;
goto read_failed;
} else {
HeapTuple rd_indextuple = (HeapTuple)readbuf;
rd_indextuple->t_data = (HeapTupleHeader)((char*)rd_indextuple + HEAPTUPLESIZE);
Form_pg_index rd_index = (Form_pg_index)GETSTRUCT(rd_indextuple);
/* Form_pg_index struct */
fprintf(stdout, "%s pg_index tuple data >>:\n", indents[2]);
ParsePgIndexTupleData((binary)rd_index, len, NULL, Natts_pg_index);
}
/* next, read the access method tuple form */
if (fread(&len, 1, sizeof(len), fp) != sizeof(len)) {
result = false;
goto read_failed;
}
Assert(len <= readbuf_size);
if (fread(readbuf, 1, len, fp) != len) {
result = false;
goto read_failed;
} else {
/* Form_pg_am */
fprintf(stdout, "%s pg_am tuple data >>:\n", indents[2]);
ParsePgAmTupleData((binary)readbuf, len, NULL, Natts_pg_am);
}
/*
* next:
* 1. read the vector of opfamily OIDs
* 2. read the vector of opcintype OIDs
* 3. read the vector of support procedure OIDs
* 4. read the vector of collation OIDs
* 5. read the vector of indoption values
*/
const char* oids_desc[] = {
"Opfamily OIDs", "Opcintype OIDs", "Procedure OIDs", "Collation OIDs", "Index Option"};
for (int kk = 0; kk < (int)(sizeof(oids_desc) / sizeof(oids_desc[0])); kk++) {
if (fread(&len, 1, sizeof(len), fp) != sizeof(len)) {
result = false;
goto read_failed;
}
Assert(len <= readbuf_size);
if (fread(readbuf, 1, len, fp) != len) {
result = false;
goto read_failed;
} else {
fprintf(stdout, "\n%s%s:", indents[indentLevel], oids_desc[kk]);
parse_oid_array((Oid*)readbuf, (len / sizeof(Oid)));
}
}
}
}
read_failed:
if (NULL != readbuf) {
free(readbuf);
}
if (NULL != fp) {
fclose(fp);
}
return result;
}
static int parse_filenodemap_file(char* filename)
{
char buffer[sizeof(RelMapFile)];
FILE* fd = NULL;
long size;
size_t result;
RelMapFile* mapfile = NULL;
char* pg_class_map[MAX_PG_CLASS_ID];
char* pg_class = NULL;
int i = 0;
for (i = 0; i < MAX_PG_CLASS_ID; i++) {
pg_class_map[i] = NULL;
}
fill_filenode_map(pg_class_map);
if (NULL == (fd = fopen(filename, "rb"))) {
fprintf(stderr, "%s: %s\n", filename, strerror(errno));
return false;
}
fseek(fd, 0, SEEK_END);
size = ftell(fd);
rewind(fd);
result = fread(buffer, 1, sizeof(RelMapFile), fd);
if (sizeof(RelMapFile) != result) {
fprintf(stderr, "Reading error");
return false;
}
mapfile = (RelMapFile*)buffer;
fprintf(stdout, "Magic number: 0x%x\n", mapfile->magic);
fprintf(stdout, "Number of mappings: %u\n", mapfile->num_mappings);
fprintf(stdout, "Mapping pairs:\n");
for (i = 0; i < MAX_MAPPINGS; i++) {
if (0 == mapfile->mappings[i].mapoid && 0 == mapfile->mappings[i].mapfilenode)
break;
if (mapfile->mappings[i].mapoid > MAX_PG_CLASS_ID)
fprintf(stderr,
"the oid(%u) of catalog is bigger than MAX_PG_CLASS_ID(%u)\n",
mapfile->mappings[i].mapoid,
MAX_PG_CLASS_ID);
pg_class = pg_class_map[mapfile->mappings[i].mapoid];
fprintf(stdout,
"\t[%d] relid: %u, relfilenode: %u, catalog: %s\n",
i,
mapfile->mappings[i].mapoid,
mapfile->mappings[i].mapfilenode,
pg_class);
}
fclose(fd);
return true;
}
/* parse a cu data hearder for cu file */
static int parse_cu_file(char* filename, uint64 offset)
{
char fullpath[1024];
FILE* fd = NULL;
int seg_num = 0;
int seg_offset = 0;
char buffer[BLCKSZ];
size_t result;
int pos = 0;
/* cu header */
int crc = 0;
uint32 magic = 0;
uint16 infoMode = 0;
uint16 bpNullCompressedSize = 0;
uint32 srcDataSize = 0;
int cmprDataSize = 0;
seg_num = offset / (RELSEG_SIZE * BLCKSZ);
seg_offset = offset % (RELSEG_SIZE * BLCKSZ);
sprintf(fullpath, "%s.%d", filename, seg_num);
if (NULL == (fd = fopen(fullpath, "rb"))) {
fprintf(stderr, "%s: %s\n", fullpath, strerror(errno));
return false;
}
fseek(fd, seg_offset, SEEK_SET);
result = fread(buffer, 1, BLCKSZ, fd);
if (result != BLCKSZ) {
fprintf(stderr, "Reading error");
return false;
}
fprintf(stdout, "CU file name: %s\n", fullpath);
fprintf(stdout, "CU data offset: %lu\n", offset);
fprintf(stdout, "CU file offset: %d\n", seg_offset);
crc = *(int32*)(buffer + pos);
pos += sizeof(crc);
fprintf(stdout, "CU data crc: 0x%X\n", crc);
magic = *(uint32*)(buffer + pos);
pos += sizeof(magic);
fprintf(stdout, "CU data magic: %u\n", magic);
infoMode = *(int16*)(buffer + pos);
pos += sizeof(infoMode);
fprintf(stdout, "CU data infoMode: 0x%X\n", infoMode);
if (infoMode & CU_HasNULL) {
bpNullCompressedSize = *(int16*)(buffer + pos);
pos += sizeof(bpNullCompressedSize);
fprintf(stdout, "CU data infoMode has NULL, NullCompressedSize: %d\n", bpNullCompressedSize);
} else
fprintf(stdout, "CU data infoMode has not NULL, NullCompressedSize: %d\n", bpNullCompressedSize);
srcDataSize = *(int32*)(buffer + pos);
pos += sizeof(srcDataSize);
fprintf(stdout, "CU data srcDataSize: %d\n", srcDataSize);
cmprDataSize = *(int*)(buffer + pos);
pos += sizeof(cmprDataSize);
fprintf(stdout, "CU data cmprDataSize: %u\n", cmprDataSize);
fclose(fd);
return true;
}
/* parse a replslot file */
static int parse_slot_file(char* filename)
{
FILE* fd = NULL;
ReplicationSlotOnDisk cp;
size_t readBytes = 0;
pg_crc32 checksum = 0;
if (NULL == (fd = fopen(filename, "rb"))) {
fprintf(stderr, "%s: %s\n", filename, strerror(errno));
return false;
}
/* read part of statefile that's guaranteed to be version independent */
readBytes = fread(&cp, 1, ReplicationSlotOnDiskConstantSize, fd);
if (readBytes != ReplicationSlotOnDiskConstantSize) {
fprintf(stderr, "Reading error");
return false;
}
/* verify magic */
if (cp.magic != SLOT_MAGIC) {
fprintf(stderr, "wrong magic");
return false;
}
/* verify version */
if (cp.version != SLOT_VERSION) {
fprintf(stderr, "unsupported version");
return false;
}
/* boundary check on length */
if (cp.length != ReplicationSlotOnDiskDynamicSize) {
fprintf(stderr, "corrupted length");
return false;
}
readBytes = fread((char*)&cp + ReplicationSlotOnDiskConstantSize, 1, cp.length, fd);
if (readBytes != cp.length) {
fprintf(stderr, "Reading error");
return false;
}
/* now verify the CRC32C */
/* using CRC32C since V1R8C10 */
INIT_CRC32C(checksum);
COMP_CRC32C(checksum, (char*)&cp + ReplicationSlotOnDiskConstantSize, ReplicationSlotOnDiskDynamicSize);
FIN_CRC32C(cp.checksum);
if (!EQ_CRC32C(checksum, cp.checksum)) {
fprintf(stderr, "slot crc error");
return false;
}
/* print slot */
fprintf(stdout, "slot name: %s\n", cp.slotdata.name.data);
fprintf(stdout, "magic: %u\n", cp.magic);
fprintf(stdout, "checksum: %u\n", cp.checksum);
fprintf(stdout, "version: %u\n", cp.version);
fprintf(stdout, "length: %u\n", cp.length);
fprintf(stdout, "database oid: %u\n", cp.slotdata.database);
fprintf(stdout, "isDummyStandby: %d\n", cp.slotdata.isDummyStandby);
fprintf(stdout, "xmin: %lu\n", cp.slotdata.xmin);
fprintf(
stdout, "restart_lsn: %X/%X\n", (uint32)(cp.slotdata.restart_lsn >> 32), (uint32)(cp.slotdata.restart_lsn));
fclose(fd);
return true;
}
/* parse gaussdb.state file */
static int parse_gaussdb_state_file(char* filename)
{
FILE* fd = NULL;
GaussState state;
size_t readBytes = 0;
char* ServerModeStr[] = {"unknown", "normal", "primary", "standby", "pending"};
char* DbStateStr[] = {"unknown",
"normal",
"needrepair",
"starting",
"waiting",
"demoting",
"promoting",
"building",
"Catchup",
"Coredump"};
char* HaRebuildReasonStr[] = {"none", "walsegment", "connect", "timeline", "systemid", "version", "mode"};
char* BuildModeStr[] = {"node", "auto", "full", "incremental"};
XLogRecPtr lsn;
uint32 term;
if (NULL == (fd = fopen(filename, "rb"))) {
fprintf(stderr, "%s: %s\n", filename, strerror(errno));
return false;
}
readBytes = fread(&state, 1, sizeof(GaussState), fd);
if (readBytes != sizeof(GaussState)) {
fprintf(stderr, "Reading error");
return false;
}
lsn = state.lsn;
term = state.term;
fprintf(stdout, "gaussdb.state info: \n");
fprintf(stdout, "ServerMode: %s\n", ServerModeStr[state.mode]);
fprintf(stdout, "conn_num: %d\n", state.conn_num);
fprintf(stdout, "DbState: %s\n", DbStateStr[state.state]);
fprintf(stdout, "sync_stat: %d\n", state.sync_stat);
fprintf(stdout, "lsn: %X/%X\n", (uint32)(lsn >> 32), (uint32)lsn);
fprintf(stdout, "term: %u\n", term);
fprintf(stdout, "ha_rebuild_reason: %s\n", HaRebuildReasonStr[state.ha_rebuild_reason]);
fprintf(stdout, "Build mode: %s\n", BuildModeStr[state.build_info.build_mode]);
fprintf(stdout, "Build total done: %lu\n", state.build_info.total_done);
fprintf(stdout, "Build total szie: %lu\n", state.build_info.total_size);
fprintf(stdout, "Build schedule: %d%%\n", state.build_info.process_schedule);
if (state.build_info.estimated_time == -1)
fprintf(stdout, "Build remain time: %s\n", "--:--:--");
else
fprintf(stdout,
"Build remain time: %.2d:%.2d:%.2d\n",
state.build_info.estimated_time / S_PER_H,
(state.build_info.estimated_time % S_PER_H) / S_PER_MIN,
(state.build_info.estimated_time % S_PER_H) % S_PER_MIN);
fclose(fd);
return true;
}
/* parse pg_control file */
static int parse_pg_control_file(char* filename)
{
FILE* fd = NULL;
ControlFileData ControlFile;
size_t readBytes = 0;
char* wal_level_str[] = {"minimal", "archive", "hot_standby"};
char* db_state_str[] = {"starting up",
"shut down",
"shut down in recovery",
"shutting down",
"in crash recovery",
"in archive recovery",
"in production"};
pg_crc32c crc;
time_t time_tmp;
char pgctime_str[128];
char ckpttime_str[128];
char sysident_str[32];
const char* strftime_fmt = "%c";
if (NULL == (fd = fopen(filename, "rb"))) {
fprintf(stderr, "%s: %s\n", filename, strerror(errno));
return false;
}
readBytes = fread(&ControlFile, 1, sizeof(ControlFileData), fd);
if (readBytes != sizeof(ControlFileData)) {
fprintf(stderr, "Reading error");
return false;
}
/* Check the CRC. */
/* using CRC32C since V1R8C10 */
INIT_CRC32C(crc);
COMP_CRC32C(crc, (char*)&ControlFile, offsetof(ControlFileData, crc));
FIN_CRC32C(crc);
if (!EQ_CRC32C(crc, ControlFile.crc)) {
fprintf(stderr, "pg_control crc error");
return false;
}
time_tmp = (time_t)ControlFile.time;
strftime(pgctime_str, sizeof(pgctime_str), strftime_fmt, localtime(&time_tmp));
time_tmp = (time_t)ControlFile.checkPointCopy.time;
strftime(ckpttime_str, sizeof(ckpttime_str), strftime_fmt, localtime(&time_tmp));
/*
* Format system_identifier separately to keep platform-dependent format
* code out of the translatable message string.
*/
snprintf(sysident_str, sizeof(sysident_str), UINT64_FORMAT, ControlFile.system_identifier);
fprintf(stdout, "pg_control version number: %u\n", ControlFile.pg_control_version);
if (ControlFile.pg_control_version % 65536 == 0 && ControlFile.pg_control_version / 65536 != 0)
fprintf(stdout,
"WARNING: possible byte ordering mismatch\n"
"The byte ordering used to store the pg_control file might not match the one\n"
"used by this program. In that case the results below would be incorrect, and\n"
"the PostgreSQL installation would be incompatible with this data directory.\n");
fprintf(stdout, "Catalog version number: %u\n", ControlFile.catalog_version_no);
fprintf(stdout, "Database system identifier: %s\n", sysident_str);
fprintf(stdout, "Database cluster state: %s\n", db_state_str[ControlFile.state]);
fprintf(stdout, "pg_control last modified: %s\n", pgctime_str);
fprintf(stdout,
"Latest checkpoint location: %X/%X\n",
(uint32)(ControlFile.checkPoint >> 32),
(uint32)ControlFile.checkPoint);
fprintf(stdout,
"Prior checkpoint location: %X/%X\n",
(uint32)(ControlFile.prevCheckPoint >> 32),
(uint32)ControlFile.prevCheckPoint);
fprintf(stdout,
"Latest checkpoint's REDO location: %X/%X\n",
(uint32)(ControlFile.checkPointCopy.redo >> 32),
(uint32)ControlFile.checkPointCopy.redo);
fprintf(stdout, "Latest checkpoint's TimeLineID: %u\n", ControlFile.checkPointCopy.ThisTimeLineID);
fprintf(
stdout, "Latest checkpoint's full_page_writes: %s\n", ControlFile.checkPointCopy.fullPageWrites ? "on" : "off");
fprintf(stdout, "Latest checkpoint's NextXID: %lu\n", ControlFile.checkPointCopy.nextXid);
fprintf(stdout, "Latest checkpoint's NextOID: %u\n", ControlFile.checkPointCopy.nextOid);
fprintf(stdout, "Latest checkpoint's NextMultiXactId: %lu\n", ControlFile.checkPointCopy.nextMulti);
fprintf(stdout, "Latest checkpoint's NextMultiOffset: %lu\n", ControlFile.checkPointCopy.nextMultiOffset);
fprintf(stdout, "Latest checkpoint's oldestXID: %lu\n", ControlFile.checkPointCopy.oldestXid);
fprintf(stdout, "Latest checkpoint's oldestXID's DB: %u\n", ControlFile.checkPointCopy.oldestXidDB);
fprintf(stdout, "Latest checkpoint's oldestActiveXID: %lu\n", ControlFile.checkPointCopy.oldestActiveXid);
fprintf(stdout, "Time of latest checkpoint: %s\n", ckpttime_str);
fprintf(stdout,
"Minimum recovery ending location: %X/%X\n",
(uint32)(ControlFile.minRecoveryPoint >> 32),
(uint32)ControlFile.minRecoveryPoint);
fprintf(stdout,
"Backup start location: %X/%X\n",
(uint32)(ControlFile.backupStartPoint >> 32),
(uint32)ControlFile.backupStartPoint);
fprintf(stdout,
"Backup end location: %X/%X\n",
(uint32)(ControlFile.backupEndPoint >> 32),
(uint32)ControlFile.backupEndPoint);
fprintf(stdout, "End-of-backup record required: %s\n", ControlFile.backupEndRequired ? "yes" : "no");
fprintf(stdout, "Current wal_level setting: %s\n", wal_level_str[(WalLevel)ControlFile.wal_level]);
fprintf(stdout, "Current max_connections setting: %d\n", ControlFile.MaxConnections);
fprintf(stdout, "Current max_prepared_xacts setting: %d\n", ControlFile.max_prepared_xacts);
fprintf(stdout, "Current max_locks_per_xact setting: %d\n", ControlFile.max_locks_per_xact);
fprintf(stdout, "Maximum data alignment: %u\n", ControlFile.maxAlign);
/* we don't print floatFormat since can't say much useful about it */
fprintf(stdout, "Database block size: %u\n", ControlFile.blcksz);
fprintf(stdout, "Blocks per segment of large relation: %u\n", ControlFile.relseg_size);
fprintf(stdout, "WAL block size: %u\n", ControlFile.xlog_blcksz);
fprintf(stdout, "Bytes per WAL segment: %u\n", ControlFile.xlog_seg_size);
fprintf(stdout, "Maximum length of identifiers: %u\n", ControlFile.nameDataLen);
fprintf(stdout, "Maximum columns in an index: %u\n", ControlFile.indexMaxKeys);
fprintf(stdout, "Maximum size of a TOAST chunk: %u\n", ControlFile.toast_max_chunk_size);
fprintf(stdout,
"Date/time type storage: %s\n",
(ControlFile.enableIntTimes ? "64-bit integers" : "floating-point numbers"));
fprintf(
stdout, "Float4 argument passing: %s\n", (ControlFile.float4ByVal ? "by value" : "by reference"));
fprintf(
stdout, "Float8 argument passing: %s\n", (ControlFile.float8ByVal ? "by value" : "by reference"));
fprintf(stdout, "Database system TimeLine: %u\n", ControlFile.timeline);
fclose(fd);
return true;
}
/* parse clog file */
static int parse_clog_file(char* filename)
{
FILE* fd = NULL;
int segnum = 0;
/* one segment file has 8k*8bit/2*32 xids */
uint32 segnum_xid = BLCKSZ * CLOG_XACTS_PER_BYTE * SLRU_PAGES_PER_SEGMENT;
/* the first xid number of current segment file */
TransactionId xid = 0;
int nread = 0;
int byte_index = 0;
int bit_index = 0;
int bshift = 0;
char* byteptr = NULL;
int status;
char* xid_status_name[] = {"IN_PROGRESS", "COMMITTED", "ABORTED", "SUB_COMMITTED"};
char buffer[8192];
if (!HexStringToInt(filename, &segnum)) {
fprintf(stderr, "%s input error \n", filename);
return false;
}
xid = (uint64)segnum * segnum_xid;
if (NULL == (fd = fopen(filename, "rb"))) {
fprintf(stderr, "%s: %s\n", filename, strerror(errno));
return false;
}
while ((nread = fread(buffer, 1, BLCKSZ, fd)) != 0) {
if (nread < 0) {
fprintf(stderr, "read file error!\n");
return false;
}
while (byte_index < nread) {
byteptr = buffer + byte_index;
for (bit_index = 0; bit_index < 4; bit_index++) {
bshift = TransactionIdToBIndex(xid) * CLOG_BITS_PER_XACT;
status = (*byteptr >> bshift) & CLOG_XACT_BITMASK;
fprintf(stdout, "xid %lu, status: %s\n", xid, xid_status_name[status]);
xid++;
}
byte_index++;
}
byte_index = 0;
}
fclose(fd);
return true;
}
/* parse subtran file */
static int parse_csnlog_file(char* filename)
{
FILE* fd = NULL;
int segnum = 0;
/* one segment file has 1k*2048 xids */
uint32 segnum_xid = CSNLOG_XACTS_PER_PAGE * SLRU_PAGES_PER_SEGMENT;
/* One page has 1k xids */
int page_xid = BLCKSZ / sizeof(CommitSeqNo);
/* the first xid number of current segment file */
TransactionId xid = 0;
CommitSeqNo csn = 0;
int nread = 0;
int entry = 0;
char buffer[8192];
if (!HexStringToInt(filename, &segnum)) {
fprintf(stderr, "%s input error \n", filename);
return false;
}
xid = (uint64)segnum * segnum_xid;
if (NULL == (fd = fopen(filename, "rb"))) {
fprintf(stderr, "%s: %s\n", filename, gs_strerror(errno));
return false;
}
while ((nread = fread(buffer, 1, BLCKSZ, fd)) != 0) {
if (nread != BLCKSZ) {
fprintf(stderr, "read file error!\n");
return false;
}
while (entry < page_xid) {
csn = *(CommitSeqNo*)(buffer + (entry * sizeof(CommitSeqNo)));
fprintf(stdout, "xid %lu, csn: %lu\n", xid, csn);
xid++;
entry++;
}
entry = 0;
}
fclose(fd);
return true;
}
static bool parse_dw_file_head(char* file_head, dw_file_head_t* saved_file_head)
{
uint32 i;
uint16 id;
dw_file_head_t *curr_head, *working_head;
working_head = NULL;
for (i = 0; i < DW_FILE_HEAD_ID_NUM; i++) {
id = g_dw_file_head_ids[i];
curr_head = (dw_file_head_t*)(file_head + (id * sizeof(dw_file_head_t)));
if (dw_verify_file_head(curr_head)) {
working_head = curr_head;
fprintf(stdout, "working head id %u\n", id);
break;
}
}
if (working_head == NULL) {
fprintf(stderr, "file head broken\n");
return false;
}
fprintf(stdout, "file_head[dwn %u, start %u]\n", working_head->head.dwn, working_head->start);
*saved_file_head = *working_head;
return true;
}
static bool read_batch_pages(
FILE* fd, dw_batch_t* curr_head, uint16 reading_pages, uint16* read_pages, uint16* file_page_id)
{
size_t result;
char* read_buf = ((char*)curr_head + *read_pages * BLCKSZ);
if (reading_pages > 0) {
/* skip the read pages */
result = fread(read_buf, BLCKSZ, reading_pages, fd);
if (result != reading_pages) {
fprintf(stderr, "read batch failed %s\n", strerror(errno));
return false;
}
*read_pages += reading_pages;
*file_page_id += reading_pages;
}
Assert(curr_head->head.page_id + *read_pages == *file_page_id);
Assert(*read_pages >= curr_head->page_num + DW_EXTRA_FOR_ONE_BATCH);
return true;
}
static bool verify_batch_continous(dw_batch_t* curr_head, uint16 dwn)
{
dw_batch_t* curr_tail = dw_batch_tail_page(curr_head);
if (dw_verify_page(curr_head) && dw_verify_page(curr_tail)) {
if (curr_head->head.dwn + 1 == curr_tail->head.dwn) {
fprintf(stdout,
"double write file truncated: batch_head[page_id %u, dwn %u, page_num %u], "
"batch_tail[page_id %u, dwn %u, page_num %u]\n",
curr_head->head.page_id,
curr_head->head.dwn,
curr_head->page_num,
curr_tail->head.page_id,
curr_tail->head.dwn,
curr_tail->page_num);
}
} else if (!dw_verify_batch(curr_head, dwn)) {
if (dw_verify_page(curr_head) && (curr_head->page_num == 0 || curr_head->head.page_id == DW_BATCH_FILE_START)) {
fprintf(stdout,
"no double write pages since last ckpt or file full: "
"batch_head[page_id %u, dwn %u, page_num %u]\n",
curr_head->head.page_id,
curr_head->head.dwn,
curr_head->page_num);
} else {
fprintf(stdout,
"double write batch broken: batch_head[page_id %u, dwn %u, page_num %u], "
"batch_tail[page_id %u, dwn %u, page_num %u]\n",
curr_head->head.page_id,
curr_head->head.dwn,
curr_head->page_num,
curr_tail->head.page_id,
curr_tail->head.dwn,
curr_tail->page_num);
}
return false;
}
return true;
}
static uint16 parse_batch_data_pages(dw_batch_t* curr_head, uint16 page_num)
{
uint16 i;
char* page_start;
BufferTag* buf_tag;
fprintf(stdout,
"batch_head[page_id %u, dwn %u, page_num %u]\n",
curr_head->head.page_id,
curr_head->head.dwn,
curr_head->page_num);
page_start = (char*)curr_head + BLCKSZ;
page_num--;
for (i = 0; i < curr_head->page_num && page_num > 0; i++, page_num--) {
buf_tag = &curr_head->buf_tag[i];
if (buf_tag->rnode.bucketNode == -1) {
fprintf(stdout,
"buf_tag[rel %u/%u/%u blk %u fork %d]\n",
buf_tag->rnode.spcNode,
buf_tag->rnode.dbNode,
buf_tag->rnode.relNode,
buf_tag->blockNum,
buf_tag->forkNum);
} else {
fprintf(stdout,
"buf_tag[rel %u/%u/%u/%d blk %u fork %d]\n",
buf_tag->rnode.spcNode,
buf_tag->rnode.dbNode,
buf_tag->rnode.relNode,
buf_tag->rnode.bucketNode,
buf_tag->blockNum,
buf_tag->forkNum);
}
parse_a_page(page_start, buf_tag->blockNum, i, SEG_UNKNOWN);
page_start += BLCKSZ;
}
return page_num;
}
static uint16 calc_reading_pages(dw_batch_t** curr_head, char* start_buf, uint16 read_pages, uint16 file_page_id)
{
uint16 buf_page_id;
errno_t rc;
dw_batch_t* batch_head = *curr_head;
int reading_pages = (batch_head->page_num + DW_EXTRA_FOR_ONE_BATCH) - read_pages;
/* next batch is already im memory, no need read */
if (reading_pages <= 0) {
reading_pages = 0;
} else {
/* buffer capacity less than uint16, cast to shorter is safe */
buf_page_id = (uint16)dw_page_distance(batch_head, start_buf);
/* buf size not enough, move the read pages to the start_buf */
/* all 3 variable less than (DW_BUF_MAX * 2), sum not overflow uint16 */
if (buf_page_id + read_pages + reading_pages >= DW_BUF_MAX) {
rc = memmove_s(start_buf, (read_pages * BLCKSZ), batch_head, (read_pages * BLCKSZ));
securec_check(rc, "\0", "\0");
*curr_head = (dw_batch_t*)start_buf;
}
}
Assert((char*)(*curr_head) + (read_pages + reading_pages) * BLCKSZ <= start_buf + DW_BUF_MAX * BLCKSZ);
Assert(file_page_id + read_pages + reading_pages <= DW_FILE_PAGE);
return (uint16)reading_pages;
}
static void parse_dw_batch(char* buf, FILE* fd, dw_file_head_t* file_head, uint16 page_num)
{
uint16 file_page_id, read_pages;
uint16 reading_pages;
uint32 flush_pages;
char* start_buf = NULL;
dw_batch_t* curr_head = NULL;
fseek(fd, (file_head->start * BLCKSZ), SEEK_SET);
file_page_id = file_head->start;
start_buf = buf;
curr_head = (dw_batch_t*)start_buf;
read_pages = 0;
reading_pages = Min(DW_BATCH_MAX, (DW_FILE_PAGE - file_page_id));
flush_pages = 0;
for (;;) {
if (!read_batch_pages(fd, curr_head, reading_pages, &read_pages, &file_page_id)) {
return;
}
/* the first read may get an empty batch */
/* but we don't know until read it */
if (curr_head->page_num == 0) {
fprintf(stdout, "no double write pages since last ckpt or file full\n");
break;
}
if (!verify_batch_continous(curr_head, file_head->head.dwn)) {
break;
}
page_num = parse_batch_data_pages(curr_head, page_num);
if (page_num == 0) {
break;
}
/* discard the first batch. including head page and data pages */
flush_pages += (1 + curr_head->page_num);
read_pages -= (1 + curr_head->page_num);
curr_head = dw_batch_tail_page(curr_head);
if (curr_head->page_num == 0) {
fprintf(stdout, "double write batch parsed: pages %u\n", flush_pages);
break;
}
reading_pages = calc_reading_pages(&curr_head, start_buf, read_pages, file_page_id);
}
}
static bool parse_dw_file(const char* file_name, uint32 start_page, uint32 page_num)
{
char* buf;
FILE* fd;
size_t result;
dw_file_head_t file_head;
fd = fopen(file_name, "rb+");
if (fd == NULL) {
fprintf(stderr, "%s: %s\n", file_name, strerror(errno));
return false;
}
buf = (char*)malloc(BLCKSZ * DW_BUF_MAX);
if (buf == NULL) {
fclose(fd);
fprintf(stderr, "out of memory\n");
return false;
}
result = fread(buf, BLCKSZ, 1, fd);
if (result != 1) {
free(buf);
fclose(fd);
fprintf(stderr, "read %s: %s\n", file_name, strerror(errno));
return false;
}
if (!parse_dw_file_head(buf, &file_head)) {
free(buf);
fclose(fd);
return false;
}
if (start_page != 0) {
Assert(start_page < DW_FILE_PAGE);
file_head.start = (uint16)start_page;
if (page_num != 0) {
fprintf(stdout, "start_page and page_num are set, hacking from %u, num %u\n", start_page, page_num);
} else {
fprintf(stdout, "start_page is set, page_num not set, hacking from %u, until end\n", start_page);
}
}
if (page_num == 0) {
page_num = DW_FILE_PAGE - start_page;
}
parse_dw_batch(buf, fd, &file_head, (uint16)page_num);
free(buf);
fclose(fd);
return true;
}
static bool dw_verify_item(const dw_single_flush_item* item, uint16 dwn)
{
if (item->data_page_idx == 0 || item->dwn != dwn) {
return false;
}
pg_crc32c crc;
/* Contents are protected with a CRC */
INIT_CRC32C(crc);
COMP_CRC32C(crc, (char*)item, offsetof(dw_single_flush_item, crc));
FIN_CRC32C(crc);
if (EQ_CRC32C(crc, item->crc)) {
return true;
} else {
return false;
}
}
static bool parse_dw_single_flush_file(const char* file_name)
{
FILE* fd;
size_t result;
dw_single_flush_item *item = (dw_single_flush_item*)malloc(sizeof(dw_single_flush_item) *
DW_SINGLE_DIRTY_PAGE_NUM);
uint16 batch_size = SINGLE_BLOCK_TAG_NUM;
uint16 blk_num = (DW_SINGLE_DIRTY_PAGE_NUM / batch_size) + (DW_SINGLE_DIRTY_PAGE_NUM % batch_size == 0 ? 0 : 1);
char *unaligned_buf = (char *)malloc((blk_num + 1 + 1) * BLCKSZ);
char *buf = (char *)TYPEALIGN(BLCKSZ, unaligned_buf);
char *file_head = buf;
buf = buf + BLCKSZ;
char *item_buf = buf;
char *unaligned_buf2 = (char *)malloc(BLCKSZ + BLCKSZ); /* one more BLCKSZ for alignment */
char *dw_block = (char *)TYPEALIGN(BLCKSZ, unaligned_buf2);
if (NULL == (fd = fopen(file_name, "rb"))) {
fprintf(stderr, "%s: %s\n", file_name, gs_strerror(errno));
return false;
}
/* read all buffer tag item, need skip head page */
fseek(fd, 0, SEEK_SET);
result = fread(file_head, 1, BLCKSZ, fd);
if (BLCKSZ != result) {
fprintf(stderr, "Reading error");
return false;
}
fseek(fd, BLCKSZ, SEEK_SET);
result = fread(item_buf, 1, blk_num * BLCKSZ, fd);
if (blk_num * BLCKSZ != result) {
fprintf(stderr, "Reading error");
return false;
}
int offset = 0;
int num = 0;
dw_single_flush_item *temp = NULL;
uint16 head_dwn = ((dw_file_head_t*)file_head)->head.dwn;
for (int i = 0; i < blk_num; i++) {
for (int j = i * batch_size; j < (i + 1) * batch_size; j++) {
offset = BLCKSZ * i + j % SINGLE_BLOCK_TAG_NUM * sizeof(dw_single_flush_item);
temp = (dw_single_flush_item*)((char*)buf + offset);
if (temp->data_page_idx != 0) {
fprintf(stdout,
"flush_item[data_page_idx %u, dwn %u, crc %u]\n",
temp->data_page_idx,
temp->dwn,
temp->crc);
if (!dw_verify_item(temp, head_dwn)) {
fprintf(stdout, "flush item check failed, not need recovery \n");
} else {
item[num].data_page_idx = temp->data_page_idx;
item[num].dwn = temp->dwn;
item[num].buf_tag = temp->buf_tag;
item[num].crc = temp->crc;
num++;
}
if (temp->buf_tag.rnode.bucketNode == -1) {
fprintf(stdout,
"buf_tag[rel %u/%u/%u blk %u fork %d]\n",
temp->buf_tag.rnode.spcNode,
temp->buf_tag.rnode.dbNode,
temp->buf_tag.rnode.relNode,
temp->buf_tag.blockNum,
temp->buf_tag.forkNum);
} else {
fprintf(stdout,
"buf_tag[rel %u/%u/%u/%d blk %u fork %d]\n",
temp->buf_tag.rnode.spcNode,
temp->buf_tag.rnode.dbNode,
temp->buf_tag.rnode.relNode,
temp->buf_tag.rnode.bucketNode,
temp->buf_tag.blockNum,
temp->buf_tag.forkNum);
}
}
}
}
for (int i = 0; i < num; i++) {
int idx = item[i].data_page_idx;
fseek(fd, (162 + idx) * BLCKSZ, SEEK_SET);
result = fread(dw_block, 1, BLCKSZ, fd);
if (BLCKSZ != result) {
fprintf(stderr, "Reading error");
return false;
}
if (temp->buf_tag.rnode.bucketNode == -1) {
fprintf(stdout,
"buf_tag[rel %u/%u/%u blk %u fork %d]\n",
item[i].buf_tag.rnode.spcNode,
item[i].buf_tag.rnode.dbNode,
item[i].buf_tag.rnode.relNode,
item[i].buf_tag.blockNum,
item[i].buf_tag.forkNum);
} else {
fprintf(stdout,
"buf_tag[rel %u/%u/%u/%d blk %u fork %d]\n",
item[i].buf_tag.rnode.spcNode,
item[i].buf_tag.rnode.dbNode,
item[i].buf_tag.rnode.relNode,
item[i].buf_tag.rnode.bucketNode,
item[i].buf_tag.blockNum,
item[i].buf_tag.forkNum);
}
parse_a_page(dw_block, item[i].buf_tag.blockNum, item[i].buf_tag.blockNum % 131072, SEG_UNKNOWN);
}
free(item);
free(unaligned_buf);
free(unaligned_buf2);
fclose(fd);
return true;
}
static void fill_filenode_map(char** class_map)
{
int i = 0;
char* name = NULL;
const PgClass_table cmap[CLASS_TYPE_NUM] = {{"pg_default_acl", 826},
{"pg_pltemplate", 1136},
{"pg_tablespace", 1213},
{"pg_shdepend", 1214},
{"pg_type", 1247},
{"pg_attribute", 1249},
{"pg_proc", 1255},
{"pg_class", 1259},
{"pg_authid", 1260},
{
"pg_auth_members",
1261,
},
{"pg_database", 1262},
{"pg_foreign_server", 1417},
{"pg_user_mapping", 1418},
{"pg_foreign_data_wrapper", 2328},
{"pg_shdescription", 2396},
{"pg_aggregate", 2600},
{
"pg_am",
2601,
},
{"pg_amop", 2602},
{"pg_amproc", 2603},
{"pg_attrdef", 2604},
{"pg_cast", 2605},
{"pg_constraint", 2606},
{"pg_conversion", 2607},
{"pg_depend", 2608},
{"pg_description", 2609},
{"pg_index", 2610},
{"pg_inherits", 2611},
{"pg_language", 2612},
{"pg_largeobject", 2613},
{"pg_namespace", 2615},
{"pg_opclass", 2616},
{"pg_operator", 2617},
{"pg_rewrite", 2618},
{"pg_statistic", 2619},
{"pg_trigger", 2620},
{"pg_opfamily", 2753},
{"pg_db_role_setting", 2964},
{"pg_largeobject_metadata", 2995},
{"pg_extension", 3079},
{"pg_foreign_table", 3118},
{"pg_enum", 3501},
{"pg_seclabel", 3596},
{"pg_ts_dict", 3600},
{"pg_ts_parser", 3601},
{"pg_ts_config", 3602},
{"pg_ts_config_map", 3603},
{"pg_ts_template", 3764},
/* normal catalogs */
{"pg_attrdef", 2830},
{"pg_attrdef", 2831},
{"pg_constraint", 2832},
{"pg_constraint", 2833},
{"pg_description", 2834},
{"pg_description", 2835},
{"pg_proc", 2836},
{"pg_proc", 2837},
{"pg_rewrite", 2838},
{"pg_rewrite", 2839},
{"pg_seclabel", 3598},
{"pg_seclabel", 3599},
{"pg_statistic", 2840},
{"pg_statistic", 2841},
{"pg_trigger", 2336},
{"pg_trigger", 2337},
/* shared catalogs */
{"pg_database", 2844},
{"pg_database", 2845},
{"pg_shdescription", 2846},
{"pg_shdescription", 2847},
{"pg_db_role_setting", 2966},
{"pg_db_role_setting", 2967},
/* indexing */
{"pg_aggregate_fnoid_index", 2650},
{"pg_am_name_index", 2651},
{"pg_am_oid_index", 2652},
{"pg_amop_fam_strat_index", 2653},
{"pg_amop_opr_fam_index", 2654},
{"pg_amop_oid_index", 2756},
{"pg_amproc_fam_proc_index", 2655},
{"pg_amproc_oid_index", 2757},
{"pg_attrdef_adrelid_adnum_index", 2656},
{"pg_attrdef_oid_index", 2657},
{"pg_attribute_relid_attnam_index", 2658},
{"pg_attribute_relid_attnum_index", 2659},
{"pg_authid_rolname_index", 2676},
{"pg_authid_oid_index", 2677},
{"pg_auth_members_role_member_index", 2694},
{"pg_auth_members_member_role_index", 2695},
{"pg_cast_oid_index", 2660},
{"pg_cast_source_target_index", 2661},
{"pg_class_oid_index", 2662},
{"pg_class_relname_nsp_index", 2663},
{"pg_collation_name_enc_nsp_index", 3164},
{"pg_collation_oid_index", 3085},
{"pg_constraint_conname_nsp_index", 2664},
{"pg_constraint_conrelid_index", 2665},
{"pg_constraint_contypid_index", 2666},
{"pg_constraint_oid_index", 2667},
{"pg_conversion_default_index", 2668},
{"pg_conversion_name_nsp_index", 2669},
{"pg_conversion_oid_index", 2670},
{"pg_database_datname_index", 2671},
{"pg_database_oid_index", 2672},
{"pg_depend_depender_index", 2673},
{"pg_depend_reference_index", 2674},
{"pg_description_o_c_o_index", 2675},
{"pg_shdescription_o_c_index", 2397},
{"pg_enum_oid_index", 3502},
{"pg_enum_typid_label_index", 3503},
{"pg_enum_typid_sortorder_index", 3534},
{"pg_index_indrelid_index", 2678},
{"pg_index_indexrelid_index", 2679},
{"pg_inherits_relid_seqno_index", 2680},
{"pg_inherits_parent_index", 2187},
{"pg_language_name_index", 2681},
{"pg_language_oid_index", 2682},
{"pg_largeobject_loid_pn_index", 2683},
{"pg_largeobject_metadata_oid_index", 2996},
{"pg_namespace_nspname_index", 2684},
{"pg_namespace_oid_index", 2685},
{"pg_opclass_am_name_nsp_index", 2686},
{"pg_opclass_oid_index", 2687},
{"pg_operator_oid_index", 2688},
{"pg_operator_oprname_l_r_n_index", 2689},
{"pg_opfamily_am_name_nsp_index", 2754},
{"pg_opfamily_oid_index", 2755},
{"pg_pltemplate_name_index", 1137},
{"pg_proc_oid_index", 2690},
{"pg_proc_proname_args_nsp_index", 2691},
{"pg_rewrite_oid_index", 2692},
{"pg_rewrite_rel_rulename_index", 2693},
{"pg_shdepend_depender_index", 1232},
{"pg_shdepend_reference_index", 1233},
{"pg_statistic_relid_att_inh_index", 2696},
{"pg_tablespace_oid_index", 2697},
{"pg_tablespace_spcname_index", 2698},
{"pg_trigger_tgconstraint_index", 2699},
{"pg_trigger_tgrelid_tgname_index", 2701},
{"pg_trigger_oid_index", 2702},
{"pg_ts_config_cfgname_index", 3608},
{"pg_ts_config_oid_index", 3712},
{"pg_ts_config_map_index", 3609},
{"pg_ts_dict_dictname_index", 3604},
{"pg_ts_dict_oid_index", 3605},
{"pg_ts_parser_prsname_index", 3606},
{"pg_ts_parser_oid_index", 3607},
{"pg_ts_template_tmplname_index", 3766},
{"pg_ts_template_oid_index", 3767},
{"pg_type_oid_index", 2703},
{"pg_type_typname_nsp_index", 2704},
{"pg_foreign_data_wrapper_oid_index", 112},
{"pg_foreign_data_wrapper_name_index", 548},
{"pg_foreign_server_oid_index", 113},
{"pg_foreign_server_name_index", 549},
{"pg_user_mapping_oid_index", 174},
{"pg_user_mapping_user_server_index", 175},
{"pg_foreign_table_relid_index", 3119},
{"pg_default_acl_role_nsp_obj_index", 827},
{"pg_default_acl_oid_index", 828},
{"pg_db_role_setting_databaseid_rol_index", 2965},
{"pg_seclabel_object_index", 3597},
{"pg_extension_oid_index", 3080},
{"pg_extension_name_index", 3081},
{"pg_auth_history", 3457},
{"pg_user_status", 3460},
{"pg_shseclabel", 3592},
{"pg_shseclabel_object_index", 3593},
{"pg_auth_history_index", 3458},
{"pg_auth_history_oid_index", 3459},
{"pg_user_status_index", 3461},
{"pg_user_status_oid_index", 3462},
{"pg_job_oid_index", 3466},
{"pg_job_proc_oid_index", 3467},
{"pg_job_schedule_oid_index", 3468},
{"pg_job_jobid_index", 3469},
{"pg_job_proc_procid_index", 3470},
{"pg_job_schedule_schid_index", 3471},
{"pg_directory_oid_index", 3223},
{"pg_directory_dirname_index", 3224},
{"pg_proc_lang_index", 3225},
{"pg_proc_lang_namespace_index", 3226},
{"pg_job", 9000},
{"pg_job_schedule", 9001},
{"pg_job_proc", 9002},
{"pg_directory", 3222},
{"pgxc_node", 9015 /* PgxcNodeRelationId */},
{"pgxc_group", 9014 /* PgxcGroupRelationId */},
{"pg_resource_pool", 3450 /* ResourcePoolRelationId */},
{"pg_workload_group", 3451 /* WorkloadGroupRelationId */},
{"pg_app_workloadgroup_mapping", 3464 /* AppWorkloadGroupMappingRelationId */},
{"pgxc_node_oid_index", 9010},
{"pgxc_node_name_index", 9011},
{"pg_extension_data_source_oid_index", 2717},
{"pg_extension_data_source_name_index", 2718}};
for (i = 0; i < CLASS_TYPE_NUM; i++) {
name = (char*)malloc(64 * sizeof(char));
if (NULL == name) {
printf("error allocate space\n");
return;
}
if (NULL != cmap[i].class_name) {
memcpy(name, cmap[i].class_name, strlen(cmap[i].class_name) + 1);
class_map[cmap[i].ralation_id] = name;
name = NULL;
} else {
free(name);
name = NULL;
}
}
return;
}
int main(int argc, char** argv)
{
int c;
char* filename = NULL;
char* env = NULL;
const char* progname = NULL;
uint32 start_point = 0;
uint32 num_block = 0;
uint64 cu_offset = 0;
progname = get_progname(argv[0]);
if (argc > 1) {
if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0 || strcmp(argv[1], "-h") == 0) {
usage(progname);
exit(0);
}
if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0) {
puts("pagehack (PostgreSQL) " PG_VERSION);
exit(0);
}
}
#ifdef WIN32
/* stderr is buffered on Win32. */
setvbuf(stderr, NULL, _IONBF, 0);
#endif
while ((c = getopt(argc, argv, "bf:o:t:vs:n:r:i:I:N:uwd")) != -1) {
switch (c) {
case 'f':
filename = optarg;
break;
case 't': {
int i;
for (i = 0; i < NUM_HACKINGTYPE; ++i) {
if (strcmp(optarg, HACKINGTYPE[i]) == 0)
break;
}
hackingtype = (HackingType)i;
if (hackingtype >= NUM_HACKINGTYPE) {
fprintf(stderr, "invalid hacking type (-t): %s\n", optarg);
exit(1);
}
break;
}
case 'o':
cu_offset = (uint64)atoll(optarg);
break;
case 'r': // relation name given
{
int i = 0;
int n = sizeof(PgHeapRelName) / sizeof(PgHeapRelName[0]);
for (; i < n; ++i) {
if (strcmp(optarg, PgHeapRelName[i]) == 0)
break;
}
if (i == n) {
fprintf(stderr, "invalid heap relation name (-r): %s\n", optarg);
exit(1);
}
PgHeapRelTupleParserCursor = i;
hackingtype = HACKING_HEAP;
break;
}
case 'u': {
hackingtype = HACKING_DW;
break;
}
case 'i': // index name given
{
int i = 0;
int n = sizeof(PgBtreeIndexRelName) / sizeof(PgBtreeIndexRelName[0]);
for (; i < n; ++i) {
if (strcmp(optarg, PgBtreeIndexRelName[i]) == 0)
break;
}
if (i == n) {
fprintf(stderr, "invalid index relation name (-i): %s\n", optarg);
exit(1);
}
PgIndexRelTupleParserCursor = i;
hackingtype = HACKING_INDEX;
break;
}
case 'v':
only_vm = true;
break;
case 'b':
only_bcm = true;
break;
case 's':
start_point = (unsigned)atoi(optarg);
break;
case 'n':
num_block = (unsigned)atoi(optarg);
break;
case 'I':
start_item = (unsigned)atoi(optarg);
break;
case 'N':
num_item = (unsigned)atoi(optarg);
break;
case 'w':
write_back = true;
break;
case 'd':
dirty_page = true;
break;
default:
fprintf(stderr, _("Try \"%s --help\" for more information.\n"), progname);
exit(1);
break;
}
}
if (NULL == filename) {
fprintf(stderr, "must specify a file to parse.\n");
exit(1);
}
if (only_vm && (hackingtype > HACKING_INDEX)) {
fprintf(stderr, "Only heap file and index file have visibility map info.\n");
exit(1);
}
if (only_bcm && (hackingtype > HACKING_INDEX)) {
fprintf(stderr, "Only heap file and index file have bcm map info.\n");
exit(1);
}
if (((start_point != 0) || (num_block != 0)) &&
/* only heap/index/undo/dw */
(hackingtype > HACKING_UNDO && hackingtype != HACKING_DW)) {
fprintf(stderr, "Start point or block number only takes effect when hacking heap/undo/index.\n");
start_point = num_block = 0;
}
if (((start_point != 0) || (num_block != 0)) && (only_vm == true)) {
fprintf(stderr, "can't show only visibility map info when hack partial relation.\n");
exit(1);
}
if (argc > optind)
pgdata = argv[optind];
else {
if ((env = getenv("GAUSSDATA")) != NULL && *env != '\0')
pgdata = env;
}
// if heap relation name is given (-r), force hackingtype to be HACKING_HEAP
if (PgHeapRelTupleParserCursor >= 0) {
hackingtype = HACKING_HEAP;
}
switch (hackingtype) {
case HACKING_HEAP:
if (!parse_page_file(filename, SEG_HEAP, start_point, num_block)) {
fprintf(stderr, "Error during parsing heap file %s.\n", filename);
exit(1);
}
break;
case HACKING_INDEX:
if (!parse_page_file(filename, SEG_INDEX_BTREE, start_point, num_block)) {
fprintf(stderr, "Error during parsing index file %s\n", filename);
exit(1);
}
break;
case HACKING_UNDO:
if (!parse_page_file(filename, SEG_UNDO, start_point, num_block)) {
fprintf(stderr, "Error during parsing heap file %s\n", filename);
exit(1);
}
break;
case HACKING_FILENODE:
if (!parse_filenodemap_file(filename)) {
fprintf(stderr, "Error during parsing filenode_map file %s\n", filename);
exit(1);
}
break;
case HACKING_INTERNAL_INIT:
if (!parse_internal_init_file(filename)) {
fprintf(stderr, "Error during parsing \"%s\" file\n", filename);
exit(1);
}
break;
case HACKING_CU:
if (!parse_cu_file(filename, cu_offset)) {
fprintf(stderr, "Error during parsing cu file %s\n", filename);
exit(1);
}
break;
case HACKING_SLOT:
if (!parse_slot_file(filename)) {
fprintf(stderr, "Error during parsing slot file %s\n", filename);
exit(1);
}
break;
case HACKING_STATE:
if (!parse_gaussdb_state_file(filename)) {
fprintf(stderr, "Error during parsing gaussdb.state file %s\n", filename);
exit(1);
}
break;
case HACKING_CONTROL:
if (!parse_pg_control_file(filename)) {
fprintf(stderr, "Error during parsing pg_control file %s\n", filename);
exit(1);
}
break;
case HACKING_CLOG:
if (!parse_clog_file(filename)) {
fprintf(stderr, "Error during parsing clog file %s\n", filename);
exit(1);
}
break;
case HACKING_CSNLOG:
if (!parse_csnlog_file(filename)) {
fprintf(stderr, "Error during parsing suntran file %s\n", filename);
exit(1);
}
break;
case HACKING_DW:
if (!parse_dw_file(filename, start_point, num_block)) {
fprintf(stderr, "Error during parsing double write file %s\n", filename);
exit(1);
}
break;
case HACKING_DW_SINGLE:
if (!parse_dw_single_flush_file(filename)) {
fprintf(stderr, "Error during parsing dw single flush file %s\n", filename);
exit(1);
}
break;
default:
/* should be impossible to be here */
Assert(false);
}
return 0;
}