Support decoding of catalog tables.

Support decoding of 'name' and 'char' types. Also introduce '~'
pseudo-type which just ignores all data left in current tuple during
decoding. These two types allow easily to decode catalog tables and
restore schema of a database even if it's corrupted and PostgreSQL
instance is not starting.

For instance, pg_attribute can be decoded like this:

pg_filedump -D oid,name,oid,int,smallint,~ path/to/segment/1249

Aleksander Alekseev
This commit is contained in:
Teodor Sigaev 2017-03-01 15:08:09 +03:00
parent 52fa0201f9
commit 5c5ba458fa
3 changed files with 91 additions and 6 deletions

View File

@ -71,8 +71,36 @@ The following options are valid for heap and index files:
off all formatting options)
-d Display formatted block content dump (Option will turn off
all other formatting options)
-D Try to decode tuples using provided list of attribute types.
[attrlist] should be something like int,timestamp,bool,uuid
-D Try to decode tuples using given comma separated list of types.
List of supported types:
* bigint
* bigserial
* bool
* char
* charN -- char(n)
* date
* float
* float4
* float8
* int
* json
* macaddr
* name
* oid
* real
* serial
* smallint
* smallserial
* text
* time
* timestamp
* timetz
* uuid
* varchar
* varcharN -- varchar(n)
* xid
* xml
* ~ -- ignores are attributes left in a tuple
-f Display formatted block content dump along with interpretation
-h Display this information
-i Display interpreted item details

View File

@ -54,6 +54,15 @@ decode_macaddr(const char* buffer, unsigned int buff_size, unsigned int* out_siz
static int
decode_string(const char* buffer, unsigned int buff_size, unsigned int* out_size);
static int
decode_char(const char* buffer, unsigned int buff_size, unsigned int* out_size);
static int
decode_name(const char* buffer, unsigned int buff_size, unsigned int* out_size);
static int
decode_ignore(const char* buffer, unsigned int buff_size, unsigned int* out_size);
static int ncallbacks = 0;
static decode_callback_t callbacks[ATTRTYPES_STR_MAX_LEN / 2] = { NULL };
@ -66,6 +75,8 @@ static ParseCallbackTableItem callback_table[] = {
{ "smallserial", &decode_smallint },
{ "smallint", &decode_smallint },
{ "int", &decode_int },
{ "oid", &decode_int },
{ "xid", &decode_int },
{ "serial", &decode_int },
{ "bigint", &decode_bigint },
{ "bigserial", &decode_bigint },
@ -73,16 +84,21 @@ static ParseCallbackTableItem callback_table[] = {
{ "timetz", &decode_timetz },
{ "date", &decode_date },
{ "timestamp", &decode_timestamp },
{ "real", &decode_float4 },
{ "float4", &decode_float4 },
{ "float8", &decode_float8 },
{ "float", &decode_float8 },
{ "bool", &decode_bool },
{ "uuid", &decode_uuid },
{ "macaddr", &decode_macaddr },
{ "name", &decode_name },
{ "char", &decode_char },
{ "~", &decode_ignore },
/* internally all string types are stored the same way */
{ "char", &decode_string },
{ "charN", &decode_string },
{ "varchar", &decode_string },
{ "varcharN", &decode_string },
{ "text", &decode_string },
{ "json", &decode_string },
{ "xml", &decode_string },
@ -654,6 +670,47 @@ decode_bool(const char* buffer, unsigned int buff_size, unsigned int* out_size)
return 0;
}
/* Decode a name type (used mostly in catalog tables) */
static int
decode_name(const char* buffer, unsigned int buff_size, unsigned int* out_size)
{
const char* new_buffer = (const char*)TYPEALIGN(sizeof(uint32), (uintptr_t)buffer);
unsigned int delta = (unsigned int)( (uintptr_t)new_buffer - (uintptr_t)buffer );
if(buff_size < delta)
return -1;
buff_size -= delta;
buffer = new_buffer;
if(buff_size < NAMEDATALEN)
return -2;
CopyAppendEncode(buffer, strnlen(buffer, NAMEDATALEN));
*out_size = NAMEDATALEN + delta;
return 0;
}
/* Decode a char type */
static int
decode_char(const char* buffer, unsigned int buff_size, unsigned int* out_size)
{
if(buff_size < sizeof(char))
return -2;
CopyAppendEncode(buffer, 1);
*out_size = 1;
return 0;
}
/* Ignore all data left */
static int
decode_ignore(const char* buffer, unsigned int buff_size, unsigned int* out_size)
{
*out_size = buff_size;
return 0;
}
/* Decode char(N), varchar(N), text, json or xml types */
static int
decode_string(const char* buffer, unsigned int buff_size, unsigned int* out_size)

View File

@ -116,8 +116,8 @@ DisplayOptions(unsigned int validOptions)
" off all formatting options)\n"
" -d Display formatted block content dump (Option will turn off\n"
" all other formatting options)\n"
" -D Try to decode tuples using provided list of attribute types.\n"
" [attrlist] should be something like int,timestamp,bool,uuid\n"
" -D Try to decode tuples using given comma separated list of types.\n"
" For full list of supported attribyte types see README file.\n"
" -f Display formatted block content dump along with interpretation\n"
" -h Display this information\n"
" -i Display interpreted item details\n"
@ -1002,7 +1002,7 @@ FormatItemBlock(Page page)
FormatBinary(itemSize, itemOffset);
/* Decode tuple data */
if(blockOptions & BLOCK_DECODE)
if((blockOptions & BLOCK_DECODE) && (itemFlags == LP_NORMAL))
FormatDecode(&buffer[itemOffset], itemSize);
if (x == maxOffset)