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:
parent
52fa0201f9
commit
5c5ba458fa
@ -71,8 +71,36 @@ The following options are valid for heap and index files:
|
|||||||
off all formatting options)
|
off all formatting options)
|
||||||
-d Display formatted block content dump (Option will turn off
|
-d Display formatted block content dump (Option will turn off
|
||||||
all other formatting options)
|
all other formatting options)
|
||||||
-D Try to decode tuples using provided list of attribute types.
|
-D Try to decode tuples using given comma separated list of types.
|
||||||
[attrlist] should be something like int,timestamp,bool,uuid
|
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
|
-f Display formatted block content dump along with interpretation
|
||||||
-h Display this information
|
-h Display this information
|
||||||
-i Display interpreted item details
|
-i Display interpreted item details
|
||||||
|
59
decode.c
59
decode.c
@ -54,6 +54,15 @@ decode_macaddr(const char* buffer, unsigned int buff_size, unsigned int* out_siz
|
|||||||
static int
|
static int
|
||||||
decode_string(const char* buffer, unsigned int buff_size, unsigned int* out_size);
|
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 int ncallbacks = 0;
|
||||||
static decode_callback_t callbacks[ATTRTYPES_STR_MAX_LEN / 2] = { NULL };
|
static decode_callback_t callbacks[ATTRTYPES_STR_MAX_LEN / 2] = { NULL };
|
||||||
|
|
||||||
@ -66,6 +75,8 @@ static ParseCallbackTableItem callback_table[] = {
|
|||||||
{ "smallserial", &decode_smallint },
|
{ "smallserial", &decode_smallint },
|
||||||
{ "smallint", &decode_smallint },
|
{ "smallint", &decode_smallint },
|
||||||
{ "int", &decode_int },
|
{ "int", &decode_int },
|
||||||
|
{ "oid", &decode_int },
|
||||||
|
{ "xid", &decode_int },
|
||||||
{ "serial", &decode_int },
|
{ "serial", &decode_int },
|
||||||
{ "bigint", &decode_bigint },
|
{ "bigint", &decode_bigint },
|
||||||
{ "bigserial", &decode_bigint },
|
{ "bigserial", &decode_bigint },
|
||||||
@ -73,16 +84,21 @@ static ParseCallbackTableItem callback_table[] = {
|
|||||||
{ "timetz", &decode_timetz },
|
{ "timetz", &decode_timetz },
|
||||||
{ "date", &decode_date },
|
{ "date", &decode_date },
|
||||||
{ "timestamp", &decode_timestamp },
|
{ "timestamp", &decode_timestamp },
|
||||||
|
{ "real", &decode_float4 },
|
||||||
{ "float4", &decode_float4 },
|
{ "float4", &decode_float4 },
|
||||||
{ "float8", &decode_float8 },
|
{ "float8", &decode_float8 },
|
||||||
{ "float", &decode_float8 },
|
{ "float", &decode_float8 },
|
||||||
{ "bool", &decode_bool },
|
{ "bool", &decode_bool },
|
||||||
{ "uuid", &decode_uuid },
|
{ "uuid", &decode_uuid },
|
||||||
{ "macaddr", &decode_macaddr },
|
{ "macaddr", &decode_macaddr },
|
||||||
|
{ "name", &decode_name },
|
||||||
|
{ "char", &decode_char },
|
||||||
|
{ "~", &decode_ignore },
|
||||||
|
|
||||||
/* internally all string types are stored the same way */
|
/* internally all string types are stored the same way */
|
||||||
{ "char", &decode_string },
|
{ "charN", &decode_string },
|
||||||
{ "varchar", &decode_string },
|
{ "varchar", &decode_string },
|
||||||
|
{ "varcharN", &decode_string },
|
||||||
{ "text", &decode_string },
|
{ "text", &decode_string },
|
||||||
{ "json", &decode_string },
|
{ "json", &decode_string },
|
||||||
{ "xml", &decode_string },
|
{ "xml", &decode_string },
|
||||||
@ -654,6 +670,47 @@ decode_bool(const char* buffer, unsigned int buff_size, unsigned int* out_size)
|
|||||||
return 0;
|
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 */
|
/* Decode char(N), varchar(N), text, json or xml types */
|
||||||
static int
|
static int
|
||||||
decode_string(const char* buffer, unsigned int buff_size, unsigned int* out_size)
|
decode_string(const char* buffer, unsigned int buff_size, unsigned int* out_size)
|
||||||
|
@ -116,8 +116,8 @@ DisplayOptions(unsigned int validOptions)
|
|||||||
" off all formatting options)\n"
|
" off all formatting options)\n"
|
||||||
" -d Display formatted block content dump (Option will turn off\n"
|
" -d Display formatted block content dump (Option will turn off\n"
|
||||||
" all other formatting options)\n"
|
" all other formatting options)\n"
|
||||||
" -D Try to decode tuples using provided list of attribute types.\n"
|
" -D Try to decode tuples using given comma separated list of types.\n"
|
||||||
" [attrlist] should be something like int,timestamp,bool,uuid\n"
|
" For full list of supported attribyte types see README file.\n"
|
||||||
" -f Display formatted block content dump along with interpretation\n"
|
" -f Display formatted block content dump along with interpretation\n"
|
||||||
" -h Display this information\n"
|
" -h Display this information\n"
|
||||||
" -i Display interpreted item details\n"
|
" -i Display interpreted item details\n"
|
||||||
@ -1002,7 +1002,7 @@ FormatItemBlock(Page page)
|
|||||||
FormatBinary(itemSize, itemOffset);
|
FormatBinary(itemSize, itemOffset);
|
||||||
|
|
||||||
/* Decode tuple data */
|
/* Decode tuple data */
|
||||||
if(blockOptions & BLOCK_DECODE)
|
if((blockOptions & BLOCK_DECODE) && (itemFlags == LP_NORMAL))
|
||||||
FormatDecode(&buffer[itemOffset], itemSize);
|
FormatDecode(&buffer[itemOffset], itemSize);
|
||||||
|
|
||||||
if (x == maxOffset)
|
if (x == maxOffset)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user