F.23. pageinspect — inspección de bajo nivel de páginas de bases de datos #

F.23.1. Funciones generales
F.23.2. Funciones de Heap
F.23.3. Funciones de B-Tree
F.23.4. Funciones BRIN
F.23.5. Funciones GIN
F.23.6. Funciones GiST
F.23.7. Funciones Hash

El módulo pageinspect proporciona funciones que te permiten inspeccionar el contenido de las páginas de las bases de datos a bajo nivel, lo cual es útil para fines de depuración. Todas estas funciones solo pueden ser utilizadas por superusuarios.

F.23.1. Funciones generales #

get_raw_page(relname text, fork text, blkno bigint) returns bytea

get_raw_page lee el bloque especificado de la relación indicada y devuelve una copia como un valor bytea. Esto permite obtener una única copia coherente en el tiempo del bloque. fork debe ser 'main' para la bifurcación de datos principal (main fork), 'fsm' para el mapa de espacio libre (free space map), 'vm' para el mapa de visibilidad (visibility map) o 'init' para la bifurcación de inicialización (initialization fork).

get_raw_page(relname text, blkno bigint) returns bytea

Una versión abreviada de get_raw_page, para leer de la bifurcación principal. Equivalente a get_raw_page(relname, 'main', blkno).

page_header(page bytea) returns record

page_header muestra los campos que son comunes a todas las páginas de índices y del heap de PostgreSQL.

Se debe pasar como argumento una imagen de página obtenida con get_raw_page. Por ejemplo:

test=# SELECT * FROM page_header(get_raw_page('pg_class', 0));
    lsn    | checksum | flags  | lower | upper | special | pagesize | version | prune_xid
-----------+----------+--------+-------+-------+---------+----------+---------+-----------
  0/24A1B50 |        0 |      1 |   232 |   368 |    8192 |     8192 |       4 |         0

Las columnas devueltas corresponden a los campos en la estructura PageHeaderData. Consulta src/include/storage/bufpage.h para más detalles.

El campo checksum es la suma de comprobación (checksum) almacenada en la página, que podría ser incorrecta si la página está de alguna manera corrompida. Si las sumas de comprobación de datos están desactivadas para esta instancia, entonces el valor almacenado carece de significado.

page_checksum(page bytea, blkno bigint) returns smallint

page_checksum calcula la suma de comprobación para la página, como si estuviera ubicada en el bloque indicado.

Se debe pasar como argumento una imagen de página obtenida con get_raw_page. Por ejemplo:

test=# SELECT page_checksum(get_raw_page('pg_class', 0), 0);
 page_checksum
---------------
         13443

Ten en cuenta que la suma de comprobación depende del número de bloque, por lo que se deben pasar números de bloques coincidentes (excepto cuando se realiza una depuración esotérica).

La suma de comprobación calculada con esta función se puede comparar con el campo de resultado checksum de la función page_header. Si las sumas de comprobación de datos están activadas para esta instancia, los dos valores deberían ser iguales.

fsm_page_contents(page bytea) returns text

fsm_page_contents muestra la estructura interna de nodos de una página FSM. Por ejemplo:

test=# SELECT fsm_page_contents(get_raw_page('pg_class', 'fsm', 0));

La salida es una cadena multilínea, con una línea por cada nodo del árbol binario dentro de la página. Solo se imprimen aquellos nodos que no son cero. También se imprime el puntero llamado "next", que apunta a la siguiente ranura (slot) que será devuelta por la página.

Consulta src/backend/storage/freespace/README para obtener más información sobre la estructura de una página FSM.

F.23.2. Funciones de Heap #

heap_page_items(page bytea) returns setof record

heap_page_items muestra todos los punteros de línea en una página del heap. Para aquellos punteros de línea que están en uso, también se muestran las cabeceras de las tuplas y los datos sin procesar de las mismas (raw data). Se muestran todas las tuplas, independientemente de si eran visibles para una instantánea MVCC en el momento en que se copió la página sin procesar.

Se debe pasar como argumento una imagen de página del heap obtenida con get_raw_page. Por ejemplo:

test=# SELECT * FROM heap_page_items(get_raw_page('pg_class', 0));

Consulta src/include/storage/itemid.h y src/include/access/htup_details.h para obtener explicaciones de los campos devueltos.

La función heap_tuple_infomask_flags se puede utilizar para desempaquetar los bits de flag de t_infomask y t_infomask2 para tuplas del heap.

tuple_data_split(rel_oid oid, t_data bytea, t_infomask integer, t_infomask2 integer, t_bits text [, do_detoast bool]) returns bytea[]

tuple_data_split divide los datos de la tupla en atributos de la misma manera que lo hacen los componentes internos del backend.

test=# SELECT tuple_data_split('pg_class'::regclass, t_data, t_infomask, t_infomask2, t_bits) FROM heap_page_items(get_raw_page('pg_class', 0));

Esta función debe llamarse con los mismos argumentos que los atributos devueltos por heap_page_items.

Si do_detoast es true, los atributos se descomprimirán/desasociarán (detoasted) según sea necesario. El valor por defecto es false.

heap_page_item_attrs(page bytea, rel_oid regclass [, do_detoast bool]) returns setof record

heap_page_item_attrs es equivalente a heap_page_items excepto que devuelve los datos sin procesar de la tupla como un array de atributos que opcionalmente pueden ser procesados con detoast por do_detoast, el cual es false por defecto.

Se debe pasar como argumento una imagen de página del heap obtenida con get_raw_page. Por ejemplo:

test=# SELECT * FROM heap_page_item_attrs(get_raw_page('pg_class', 0), 'pg_class'::regclass);

heap_tuple_infomask_flags(t_infomask integer, t_infomask2 integer) returns record

heap_tuple_infomask_flags decodifica los valores de t_infomask y t_infomask2 devueltos por heap_page_items en un conjunto legible por humanos de arrays formados por nombres de flags, con una columna para todos los flags y otra para los flags combinados. Por ejemplo:

test=# SELECT t_ctid, raw_flags, combined_flags
         FROM heap_page_items(get_raw_page('pg_class', 0)),
           LATERAL heap_tuple_infomask_flags(t_infomask, t_infomask2)
         WHERE t_infomask IS NOT NULL OR t_infomask2 IS NOT NULL;

Esta función debe llamarse con los mismos argumentos que los atributos de retorno de heap_page_items.

Los flags combinados se muestran para macros a nivel de código fuente que tienen en cuenta el valor de más de un bit sin procesar, como HEAP_XMIN_FROZEN.

Consulta src/include/access/htup_details.h para obtener explicaciones de los nombres de los flags devueltos.

F.23.3. Funciones de B-Tree #

bt_metap(relname text) returns record

bt_metap devuelve información sobre la metapágina de un índice B-tree. Por ejemplo:

test=# SELECT * FROM bt_metap('pg_cast_oid_index');
-[ RECORD 1 ]-------------+-------
magic                     | 340322
version                   | 4
root                      | 1
level                     | 0
fastroot                  | 1
fastlevel                 | 0
last_cleanup_num_delpages | 0
last_cleanup_num_tuples   | 230
allequalimage             | f

bt_page_stats(relname text, blkno bigint) returns record

bt_page_stats devuelve información resumida sobre una página de datos de un índice B-tree. Por ejemplo:

test=# SELECT * FROM bt_page_stats('pg_cast_oid_index', 1);
-[ RECORD 1 ]-+-----
blkno         | 1
type          | l
live_items    | 224
dead_items    | 0
avg_item_size | 16
page_size     | 8192
free_size     | 3668
btpo_prev     | 0
btpo_next     | 0
btpo_level    | 0
btpo_flags    | 3

bt_multi_page_stats(relname text, blkno bigint, blk_count bigint) returns setof record

bt_multi_page_stats devuelve la misma información que bt_page_stats, pero lo hace para cada página en el rango de páginas que comienza en blkno y se extiende durante blk_count páginas. Si blk_count es negativo, se reportan todas las páginas desde blkno hasta el final del índice. Por ejemplo:

test=# SELECT * FROM bt_multi_page_stats('pg_proc_oid_index', 5, 2);
-[ RECORD 1 ]-+-----
blkno         | 5
type          | l
live_items    | 367
dead_items    | 0
avg_item_size | 16
page_size     | 8192
free_size     | 808
btpo_prev     | 4
btpo_next     | 6
btpo_level    | 0
btpo_flags    | 1
-[ RECORD 2 ]-+-----
blkno         | 6
type          | l
live_items    | 367
dead_items    | 0
avg_item_size | 16
page_size     | 8192
free_size     | 808
btpo_prev     | 5
btpo_next     | 7
btpo_level    | 0
btpo_flags    | 1

bt_page_items(relname text, blkno bigint) returns setof record

bt_page_items devuelve información detallada sobre todos los elementos de una página de índice B-tree. Por ejemplo:

test=# SELECT itemoffset, ctid, itemlen, nulls, vars, data, dead, htid, tids[0:2] AS some_tids
        FROM bt_page_items('tenk2_hundred', 5);
 itemoffset |   ctid    | itemlen | nulls | vars |          data           | dead |  htid  |      some_tids
------------+-----------+---------+-------+------+-------------------------+------+--------+---------------------
          1 | (16,1)    |      16 | f     | f    | 30 00 00 00 00 00 00 00 |      |        |
          2 | (16,8292) |     616 | f     | f    | 24 00 00 00 00 00 00 00 | f    | (1,6)  | {"(1,6)","(10,22)"}
          3 | (16,8292) |     616 | f     | f    | 25 00 00 00 00 00 00 00 | f    | (1,18) | {"(1,18)","(4,22)"}
          4 | (16,8292) |     616 | f     | f    | 26 00 00 00 00 00 00 00 | f    | (4,18) | {"(4,18)","(6,17)"}
          5 | (16,8292) |     616 | f     | f    | 27 00 00 00 00 00 00 00 | f    | (1,2)  | {"(1,2)","(1,19)"}
          6 | (16,8292) |     616 | f     | f    | 28 00 00 00 00 00 00 00 | f    | (2,24) | {"(2,24)","(4,11)"}
          7 | (16,8292) |     616 | f     | f    | 29 00 00 00 00 00 00 00 | f    | (2,17) | {"(2,17)","(11,2)"}
          8 | (16,8292) |     616 | f     | f    | 2a 00 00 00 00 00 00 00 | f    | (0,25) | {"(0,25)","(3,20)"}
          9 | (16,8292) |     616 | f     | f    | 2b 00 00 00 00 00 00 00 | f    | (0,10) | {"(0,10)","(0,14)"}
         10 | (16,8292) |     616 | f     | f    | 2c 00 00 00 00 00 00 00 | f    | (1,3)  | {"(1,3)","(3,9)"}
         11 | (16,8292) |     616 | f     | f    | 2d 00 00 00 00 00 00 00 | f    | (6,28) | {"(6,28)","(11,1)"}
         12 | (16,8292) |     616 | f     | f    | 2e 00 00 00 00 00 00 00 | f    | (0,27) | {"(0,27)","(1,13)"}
         13 | (16,8292) |     616 | f     | f    | 2f 00 00 00 00 00 00 00 | f    | (4,17) | {"(4,17)","(4,21)"}
(13 rows)

Esta es una página hoja de un B-tree. Todas las tuplas que apuntan a la tabla resultan ser tuplas de tipo posting list (todas ellas almacenan un total de 100 TIDs de 6 bytes). También hay una tupla high key (clave alta) en el itemoffset número 1. En este ejemplo se utiliza ctid para almacenar información codificada sobre cada tupla, aunque las tuplas de página hoja suelen almacenar un TID del heap directamente en el campo ctid. tids es la lista de TIDs almacenada como una posting list.

En una página interna (no mostrada), la parte del número de bloque de ctid es un downlink (enlace descendente), que es el número de bloque de otra página del propio índice. La parte de desplazamiento (el segundo número) de ctid almacena información codificada sobre la tupla, como el número de columnas presentes (la truncación de sufijos puede haber eliminado columnas de sufijo innecesarias). Las columnas truncadas se tratan como si tuvieran el valor menos infinito.

htid muestra un TID de heap para la tupla, independientemente de la representación de la tupla subyacente. Este valor puede coincidir con ctid, o puede ser decodificado a partir de las representaciones alternativas utilizadas por las tuplas de tipo posting list y las tuplas de páginas internas. Las tuplas en páginas internas suelen tener la columna TID del heap de nivel de implementación truncada, lo que se representa como un valor htid NULL.

Ten en cuenta que el primer elemento en cualquier página que no sea la de más a la derecha (cualquier página con un valor distinto de cero en el campo btpo_next) es la high key de la página, lo que significa que sus datos (data) sirven como un límite superior para todos los elementos que aparecen en la página, mientras que su campo ctid no apunta a otro bloque. Además, en las páginas internas, el primer elemento de datos reales (el primer elemento que no es una clave alta) tiene de manera confiable todas las columnas truncadas, no dejando ningún valor real en su campo data. Sin embargo, dicho elemento sí tiene un downlink válido en su campo ctid.

Para obtener más detalles sobre la estructura de los índices B-tree, consulta Section 65.1.4.1. Para obtener más detalles sobre la deduplicación y las posting lists, consulta la Section 65.1.4.3.

bt_page_items(page bytea) returns setof record

También es posible pasar una página a bt_page_items como un valor bytea. Se debe pasar como argumento una imagen de página obtenida con get_raw_page. Por lo tanto, el último ejemplo también podría reescribirse de esta manera:

test=# SELECT itemoffset, ctid, itemlen, nulls, vars, data, dead, htid, tids[0:2] AS some_tids
        FROM bt_page_items(get_raw_page('tenk2_hundred', 5));
 itemoffset |   ctid    | itemlen | nulls | vars |          data           | dead |  htid  |      some_tids
------------+-----------+---------+-------+------+-------------------------+------+--------+---------------------
          1 | (16,1)    |      16 | f     | f    | 30 00 00 00 00 00 00 00 |      |        |
          2 | (16,8292) |     616 | f     | f    | 24 00 00 00 00 00 00 00 | f    | (1,6)  | {"(1,6)","(10,22)"}
          3 | (16,8292) |     616 | f     | f    | 25 00 00 00 00 00 00 00 | f    | (1,18) | {"(1,18)","(4,22)"}
          4 | (16,8292) |     616 | f     | f    | 26 00 00 00 00 00 00 00 | f    | (4,18) | {"(4,18)","(6,17)"}
          5 | (16,8292) |     616 | f     | f    | 27 00 00 00 00 00 00 00 | f    | (1,2)  | {"(1,2)","(1,19)"}
          6 | (16,8292) |     616 | f     | f    | 28 00 00 00 00 00 00 00 | f    | (2,24) | {"(2,24)","(4,11)"}
          7 | (16,8292) |     616 | f     | f    | 29 00 00 00 00 00 00 00 | f    | (2,17) | {"(2,17)","(11,2)"}
          8 | (16,8292) |     616 | f     | f    | 2a 00 00 00 00 00 00 00 | f    | (0,25) | {"(0,25)","(3,20)"}
          9 | (16,8292) |     616 | f     | f    | 2b 00 00 00 00 00 00 00 | f    | (0,10) | {"(0,10)","(0,14)"}
         10 | (16,8292) |     616 | f     | f    | 2c 00 00 00 00 00 00 00 | f    | (1,3)  | {"(1,3)","(3,9)"}
         11 | (16,8292) |     616 | f     | f    | 2d 00 00 00 00 00 00 00 | f    | (6,28) | {"(6,28)","(11,1)"}
         12 | (16,8292) |     616 | f     | f    | 2e 00 00 00 00 00 00 00 | f    | (0,27) | {"(0,27)","(1,13)"}
         13 | (16,8292) |     616 | f     | f    | 2f 00 00 00 00 00 00 00 | f    | (4,17) | {"(4,17)","(4,21)"}
(13 rows)

Todos los demás detalles son los mismos explicados en el elemento anterior.

F.23.4. Funciones BRIN #

brin_page_type(page bytea) returns text

brin_page_type devuelve el tipo de página de la página de índice BRIN dada, o lanza un error si la página no es una página BRIN válida. Por ejemplo:

test=# SELECT brin_page_type(get_raw_page('brinidx', 0));
 brin_page_type
----------------
 meta

brin_metapage_info(page bytea) returns record

brin_metapage_info devuelve información diversa sobre una metapágina de índice BRIN. Por ejemplo:

test=# SELECT * FROM brin_metapage_info(get_raw_page('brinidx', 0));
   magic    | version | pagesperrange | lastrevmappage
------------+---------+---------------+----------------
 0xA8109CFA |       1 |             4 |              2

brin_revmap_data(page bytea) returns setof tid

brin_revmap_data devuelve la lista de identificadores de tuplas en una página de mapa de rango de índice BRIN (range map page). Por ejemplo:

test=# SELECT * FROM brin_revmap_data(get_raw_page('brinidx', 2)) LIMIT 5;
  pages
---------
 (6,137)
 (6,138)
 (6,139)
 (6,140)
 (6,141)

brin_page_items(page bytea, index oid) returns setof record

brin_page_items devuelve los datos almacenados en la página de datos BRIN. Por ejemplo:

test=# SELECT * FROM brin_page_items(get_raw_page('brinidx', 5),
                                     'brinidx')
       ORDER BY blknum, attnum LIMIT 6;
 itemoffset | blknum | attnum | allnulls | hasnulls | placeholder | empty |    value
------------+--------+--------+----------+----------+-------------+-------+--------------
        137 |      0 |      1 | t        | f        | f           | f     |
        137 |      0 |      2 | f        | f        | f           | f     | {1 .. 88}
        138 |      4 |      1 | t        | f        | f           | f     |
        138 |      4 |      2 | f        | f        | f           | f     | {89 .. 176}
        139 |      8 |      1 | t        | f        | f           | f     |
        139 |      8 |      2 | f        | f        | f           | f     | {177 .. 264}

Las columnas devueltas corresponden a los campos en las estructuras BrinMemTuple y BrinValues. Consulta src/include/access/brin_tuple.h para más detalles.

F.23.5. Funciones GIN #

gin_metapage_info(page bytea) returns record

gin_metapage_info devuelve información sobre una metapágina de índice GIN. Por ejemplo:

test=# SELECT * FROM gin_metapage_info(get_raw_page('gin_index', 0));
-[ RECORD 1 ]----+-----------
pending_head     | 4294967295
pending_tail     | 4294967295
tail_free_size   | 0
n_pending_pages  | 0
n_pending_tuples | 0
n_total_pages    | 7
n_entry_pages    | 6
n_data_pages     | 0
n_entries        | 693
version          | 2

gin_page_opaque_info(page bytea) returns record

gin_page_opaque_info devuelve información sobre el área opaca de un índice GIN, como el tipo de página. Por ejemplo:

test=# SELECT * FROM gin_page_opaque_info(get_raw_page('gin_index', 2));
 rightlink | maxoff |         flags
-----------+--------+------------------------
         5 |      0 | {data,leaf,compressed}
(1 row)

gin_leafpage_items(page bytea) returns setof record

gin_leafpage_items devuelve información sobre los datos almacenados en una página hoja GIN comprimida. Por ejemplo:

test=# SELECT first_tid, nbytes, tids[0:5] AS some_tids
        FROM gin_leafpage_items(get_raw_page('gin_test_idx', 2));
 first_tid | nbytes |                        some_tids
-----------+--------+----------------------------------------------------------
 (8,41)    |    244 | {"(8,41)","(8,43)","(8,44)","(8,45)","(8,46)"}
 (10,45)   |    248 | {"(10,45)","(10,46)","(10,47)","(10,48)","(10,49)"}
 (12,52)   |    248 | {"(12,52)","(12,53)","(12,54)","(12,55)","(12,56)"}
 (14,59)   |    320 | {"(14,59)","(14,60)","(14,61)","(14,62)","(14,63)"}
 (167,16)  |    376 | {"(167,16)","(167,17)","(167,18)","(167,19)","(167,20)"}
 (170,30)  |    376 | {"(170,30)","(170,31)","(170,32)","(170,33)","(170,34)"}
 (173,44)  |    197 | {"(173,44)","(173,45)","(173,46)","(173,47)","(173,48)"}
(7 rows)

F.23.6. Funciones GiST #

gist_page_opaque_info(page bytea) returns record

gist_page_opaque_info devuelve información del área opaca de una página de índice GiST, como el NSN, el rightlink y el tipo de página. Por ejemplo:

test=# SELECT * FROM gist_page_opaque_info(get_raw_page('test_gist_idx', 2));
 lsn | nsn | rightlink | flags
-----+-----+-----------+--------
 0/1 | 0/0 |         1 | {leaf}
(1 row)

gist_page_items(page bytea, index_oid regclass) returns setof record

gist_page_items devuelve información sobre los datos almacenados en una página de un índice GiST. Por ejemplo:

test=# SELECT * FROM gist_page_items(get_raw_page('test_gist_idx', 0), 'test_gist_idx');
 itemoffset |   ctid    | itemlen | dead |             keys
------------+-----------+---------+------+-------------------------------
          1 | (1,65535) |      40 | f    | (p)=("(185,185),(1,1)")
          2 | (2,65535) |      40 | f    | (p)=("(370,370),(186,186)")
          3 | (3,65535) |      40 | f    | (p)=("(555,555),(371,371)")
          4 | (4,65535) |      40 | f    | (p)=("(740,740),(556,556)")
          5 | (5,65535) |      40 | f    | (p)=("(870,870),(741,741)")
          6 | (6,65535) |      40 | f    | (p)=("(1000,1000),(871,871)")
(6 rows)

gist_page_items_bytea(page bytea) returns setof record

Lo mismo que gist_page_items, pero devuelve los datos de la clave como un blob bytea sin procesar. Dado que no intenta decodificar la clave, no necesita saber de qué índice se trata. Por ejemplo:

test=# SELECT * FROM gist_page_items_bytea(get_raw_page('test_gist_idx', 0));
 itemoffset |   ctid    | itemlen | dead |                                      key_data
------------+-----------+---------+------+------------------------------------------------------------------------------------
          1 | (1,65535) |      40 | f    | \x00000100ffff28000000000000c064400000000000c06440000000000000f03f000000000000f03f
          2 | (2,65535) |      40 | f    | \x00000200ffff28000000000000c074400000000000c074400000000000e064400000000000e06440
          3 | (3,65535) |      40 | f    | \x00000300ffff28000000000000207f400000000000207f400000000000d074400000000000d07440
          4 | (4,65535) |      40 | f    | \x00000400ffff28000000000000c084400000000000c084400000000000307f400000000000307f40
          5 | (5,65535) |      40 | f    | \x00000500ffff28000000000000f089400000000000f089400000000000c884400000000000c88440
          6 | (6,65535) |      40 | f    | \x00000600ffff28000000000000208f400000000000208f400000000000f889400000000000f88940
          7 | (7,65535) |      40 | f    | \x00000700ffff28000000000000408f400000000000408f400000000000288f400000000000288f40
(7 rows)

F.23.7. Funciones Hash #

hash_page_type(page bytea) returns text

hash_page_type devuelve el tipo de página de la página de índice HASH dada. Por ejemplo:

test=# SELECT hash_page_type(get_raw_page('con_hash_index', 0));
 hash_page_type
----------------
 metapage

hash_page_stats(page bytea) returns setof record

hash_page_stats devuelve información sobre un cubo (bucket) o una página de desbordamiento (overflow page) de un índice HASH. Por ejemplo:

test=# SELECT * FROM hash_page_stats(get_raw_page('con_hash_index', 1));
-[ RECORD 1 ]---+-----------
live_items      | 407
dead_items      | 0
page_size       | 8192
free_size       | 8
hasho_prevblkno | 4096
hasho_nextblkno | 8474
hasho_bucket    | 0
hasho_flag      | 66
hasho_page_id   | 65408

hash_page_items(page bytea) returns setof record

hash_page_items devuelve información sobre los datos almacenados en un cubo o una página de desbordamiento de un índice HASH. Por ejemplo:

test=# SELECT * FROM hash_page_items(get_raw_page('con_hash_index', 1)) LIMIT 5;
 itemoffset |   ctid    |    data
------------+-----------+------------
          1 | (899,77)  | 1053474816
          2 | (897,29)  | 1053474816
          3 | (894,207) | 1053474816
          4 | (892,159) | 1053474816
          5 | (890,111) | 1053474816

hash_bitmap_info(index oid, blkno bigint) returns record

hash_bitmap_info muestra el estado de un bit en la página de mapa de bits para una página de desbordamiento particular de un índice HASH. Por ejemplo:

test=# SELECT * FROM hash_bitmap_info('con_hash_index', 2052);
 bitmapblkno | bitmapbit | bitstatus
-------------+-----------+-----------
          65 |         3 | t

hash_metapage_info(page bytea) returns record

hash_metapage_info devuelve información almacenada en la metapágina de un índice HASH. Por ejemplo:

test=# SELECT magic, version, ntuples, ffactor, bsize, bmsize, bmshift,
test-#     maxbucket, highmask, lowmask, ovflpoint, firstfree, nmaps, procid,
test-#     regexp_replace(spares::text, '(,0)*}', '}') as spares,
test-#     regexp_replace(mapp::text, '(,0)*}', '}') as mapp
test-# FROM hash_metapage_info(get_raw_page('con_hash_index', 0));
-[ RECORD 1 ]-------------------------------------------------------------------------------
magic     | 105121344
version   | 4
ntuples   | 500500
ffactor   | 40
bsize     | 8152
bmsize    | 4096
bmshift   | 15
maxbucket | 12512
highmask  | 16383
lowmask   | 8191
ovflpoint | 28
firstfree | 1204
nmaps     | 1
procid    | 450
spares    | {0,0,0,0,0,0,1,1,1,1,1,1,1,1,3,4,4,4,45,55,58,59,508,567,628,704,1193,1202,1204}
mapp      | {65}