From fa2841b83a57daf8de95e8b154afc2bf5dd60dda Mon Sep 17 00:00:00 2001 From: Julien Rouhaud Date: Thu, 24 Mar 2022 15:51:21 +0800 Subject: [PATCH v1] pageinspect: add more sanity checks when accessing pages. As seen in bug #16527, feeding an incorrect page can lead to ouf-of-bound reads when trying to access the page special area. To fix it, check that the special area has the expected size before trying to access in in the functions that weren't already doing so. While at it, add other checks when possible to validate that the given page is from the expected format to avoid other possible invalid access. Author: Julien Rouhaud Reported-By: Alexander Lakhin Discussion: https://postgr.es/m/16527-ef7606186f0610a1%40postgresql.org Discussion: https://postgr.es/m/150535d6-65ac-16ee-b28a-851965fc485b%40gmail.com --- contrib/pageinspect/brinfuncs.c | 18 +++++++++++++ contrib/pageinspect/btreefuncs.c | 16 ++++++++++++ contrib/pageinspect/expected/brin.out | 12 +++++++++ contrib/pageinspect/expected/btree.out | 23 +++++++++++++++-- contrib/pageinspect/expected/gin.out | 9 +++++++ contrib/pageinspect/expected/gist.out | 11 ++++++++ contrib/pageinspect/expected/hash.out | 14 +++++++++++ contrib/pageinspect/ginfuncs.c | 16 ++++++++++++ contrib/pageinspect/gistfuncs.c | 35 ++++++++++++++++++++++++++ contrib/pageinspect/sql/brin.sql | 5 ++++ contrib/pageinspect/sql/btree.sql | 13 ++++++++-- contrib/pageinspect/sql/gin.sql | 3 +++ contrib/pageinspect/sql/gist.sql | 4 +++ contrib/pageinspect/sql/hash.sql | 11 ++++++++ 14 files changed, 186 insertions(+), 4 deletions(-) diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c index bf12901ac3..d4de80eee5 100644 --- a/contrib/pageinspect/brinfuncs.c +++ b/contrib/pageinspect/brinfuncs.c @@ -58,6 +58,15 @@ brin_page_type(PG_FUNCTION_ARGS) page = get_page_from_raw(raw_page); + /* verify the special space has the expected size */ + if (PageGetSpecialSize(page) != MAXALIGN(sizeof(BrinSpecialSpace))) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("input page is not a valid brin page"), + errdetail("Special size %d, expected %d", + (int) PageGetSpecialSize(page), + (int) MAXALIGN(sizeof(BrinSpecialSpace))))); + switch (BrinPageType(page)) { case BRIN_PAGETYPE_META: @@ -86,6 +95,15 @@ verify_brin_page(bytea *raw_page, uint16 type, const char *strtype) { Page page = get_page_from_raw(raw_page); + /* verify the special space has the expected size */ + if (PageGetSpecialSize(page) != sizeof(BrinSpecialSpace)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("input page is not a valid brin page"), + errdetail("Special size %d, expected %d", + (int) PageGetSpecialSize(page), + (int) MAXALIGN(sizeof(BrinSpecialSpace))))); + /* verify the special space says this page is what we want */ if (BrinPageType(page) != type) ereport(ERROR, diff --git a/contrib/pageinspect/btreefuncs.c b/contrib/pageinspect/btreefuncs.c index d9628dd664..9b618abe47 100644 --- a/contrib/pageinspect/btreefuncs.c +++ b/contrib/pageinspect/btreefuncs.c @@ -613,6 +613,15 @@ bt_page_items_bytea(PG_FUNCTION_ARGS) uargs->offset = FirstOffsetNumber; + /* verify the special space has the expected size */ + if (PageGetSpecialSize(uargs->page) != MAXALIGN(sizeof(BTPageOpaqueData))) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("input page is not a valid btree page"), + errdetail("Special size %d, expected %d", + (int) PageGetSpecialSize(uargs->page), + (int) MAXALIGN(sizeof(BTPageOpaqueData))))); + opaque = (BTPageOpaque) PageGetSpecialPointer(uargs->page); if (P_ISMETA(opaque)) @@ -620,6 +629,12 @@ bt_page_items_bytea(PG_FUNCTION_ARGS) (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("block is a meta page"))); + if (P_ISLEAF(opaque) && opaque->btpo_level != 0) + ereport(ERROR, + (errcode(ERRCODE_INDEX_CORRUPTED), + errmsg("index table contains corrupted page"), + errdetail("Page is leaf but found non-zero level"))); + if (P_ISDELETED(opaque)) elog(NOTICE, "page is deleted"); @@ -631,6 +646,7 @@ bt_page_items_bytea(PG_FUNCTION_ARGS) elog(NOTICE, "page from block is deleted"); fctx->max_calls = 0; } + uargs->leafpage = P_ISLEAF(opaque); uargs->rightmost = P_RIGHTMOST(opaque); diff --git a/contrib/pageinspect/expected/brin.out b/contrib/pageinspect/expected/brin.out index 10cd36c177..07a18feeb4 100644 --- a/contrib/pageinspect/expected/brin.out +++ b/contrib/pageinspect/expected/brin.out @@ -1,6 +1,9 @@ CREATE TABLE test1 (a int, b text); INSERT INTO test1 VALUES (1, 'one'); CREATE INDEX test1_a_idx ON test1 USING brin (a); +SELECT brin_page_type(get_raw_page('test1', 0)); +ERROR: input page is not a valid brin page +DETAIL: Special size 0, expected 8 SELECT brin_page_type(get_raw_page('test1_a_idx', 0)); brin_page_type ---------------- @@ -19,6 +22,9 @@ SELECT brin_page_type(get_raw_page('test1_a_idx', 2)); regular (1 row) +SELECT * FROM brin_metapage_info(get_raw_page('test1', 0)); +ERROR: input page is not a valid brin page +DETAIL: Special size 0, expected 8 SELECT * FROM brin_metapage_info(get_raw_page('test1_a_idx', 0)); magic | version | pagesperrange | lastrevmappage ------------+---------+---------------+---------------- @@ -28,6 +34,9 @@ SELECT * FROM brin_metapage_info(get_raw_page('test1_a_idx', 0)); SELECT * FROM brin_metapage_info(get_raw_page('test1_a_idx', 1)); ERROR: page is not a BRIN page of type "metapage" DETAIL: Expected special type 0000f091, got 0000f092. +SELECT * FROM brin_revmap_data(get_raw_page('test1', 0)); +ERROR: input page is not a valid brin page +DETAIL: Special size 0, expected 8 SELECT * FROM brin_revmap_data(get_raw_page('test1_a_idx', 0)) LIMIT 5; ERROR: page is not a BRIN page of type "revmap" DETAIL: Expected special type 0000f092, got 0000f091. @@ -41,6 +50,9 @@ SELECT * FROM brin_revmap_data(get_raw_page('test1_a_idx', 1)) LIMIT 5; (0,0) (5 rows) +SELECT * FROM brin_page_items(get_raw_page('test1', 0), 'test1') + ORDER BY blknum, attnum LIMIT 5; +ERROR: "test1" is not an index SELECT * FROM brin_page_items(get_raw_page('test1_a_idx', 2), 'test1_a_idx') ORDER BY blknum, attnum LIMIT 5; itemoffset | blknum | attnum | allnulls | hasnulls | placeholder | value diff --git a/contrib/pageinspect/expected/btree.out b/contrib/pageinspect/expected/btree.out index 80b3dfe861..b9705aaae8 100644 --- a/contrib/pageinspect/expected/btree.out +++ b/contrib/pageinspect/expected/btree.out @@ -1,7 +1,9 @@ -CREATE TABLE test1 (a int8, b text); -INSERT INTO test1 VALUES (72057594037927937, 'text'); +CREATE TABLE test1 (a int8, b int4range); +INSERT INTO test1 VALUES (72057594037927937, '[0,1)'); CREATE INDEX test1_a_idx ON test1 USING btree (a); \x +SELECT * FROM bt_metap('test1'); +ERROR: "test1" is not a btree index SELECT * FROM bt_metap('test1_a_idx'); -[ RECORD 1 ]-------------+------- magic | 340322 @@ -14,6 +16,8 @@ last_cleanup_num_delpages | 0 last_cleanup_num_tuples | -1 allequalimage | t +SELECT * FROM bt_page_stats('test1', 0); +ERROR: "test1" is not a btree index SELECT * FROM bt_page_stats('test1_a_idx', -1); ERROR: invalid block number SELECT * FROM bt_page_stats('test1_a_idx', 0); @@ -34,6 +38,8 @@ btpo_flags | 3 SELECT * FROM bt_page_stats('test1_a_idx', 2); ERROR: block number out of range +SELECT * FROM bt_page_items('test1', 0); +ERROR: "test1" is not a btree index SELECT * FROM bt_page_items('test1_a_idx', -1); ERROR: invalid block number SELECT * FROM bt_page_items('test1_a_idx', 0); @@ -52,6 +58,9 @@ tids | SELECT * FROM bt_page_items('test1_a_idx', 2); ERROR: block number out of range +SELECT * FROM bt_page_items(get_raw_page('test1', 0)); +ERROR: input page is not a valid btree page +DETAIL: Special size 0, expected 16 SELECT * FROM bt_page_items(get_raw_page('test1_a_idx', -1)); ERROR: invalid block number SELECT * FROM bt_page_items(get_raw_page('test1_a_idx', 0)); @@ -78,6 +87,16 @@ SELECT bt_page_stats('test1_a_hash', 0); ERROR: "test1_a_hash" is not a btree index SELECT bt_page_items('test1_a_hash', 0); ERROR: "test1_a_hash" is not a btree index +SELECT bt_page_items(get_raw_page('test1_a_hash', 0)); +ERROR: block is a meta page +CREATE INDEX test1_b_gist ON test1 USING gist(b); +SELECT bt_page_items(get_raw_page('test1_b_gist', 0)); +ERROR: index table contains corrupted page +DETAIL: Page is leaf but found non-zero level +CREATE INDEX test1_a_brin ON test1 USING brin(a); +SELECT bt_page_items(get_raw_page('test1_a_brin', 0)); +ERROR: input page is not a valid btree page +DETAIL: Special size 8, expected 16 -- Failure with incorrect page size -- Suppress the DETAIL message, to allow the tests to work across various -- page sizes. diff --git a/contrib/pageinspect/expected/gin.out b/contrib/pageinspect/expected/gin.out index 802f48284b..7f67d979bc 100644 --- a/contrib/pageinspect/expected/gin.out +++ b/contrib/pageinspect/expected/gin.out @@ -2,6 +2,9 @@ CREATE TABLE test1 (x int, y int[]); INSERT INTO test1 VALUES (1, ARRAY[11, 111]); CREATE INDEX test1_y_idx ON test1 USING gin (y) WITH (fastupdate = off); \x +SELECT * FROM gin_metapage_info(get_raw_page('test1', 0)); +ERROR: input page is not a valid GIN metapage +DETAIL: Special size 0, expected 8 SELECT * FROM gin_metapage_info(get_raw_page('test1_y_idx', 0)); -[ RECORD 1 ]----+----------- pending_head | 4294967295 @@ -18,12 +21,18 @@ version | 2 SELECT * FROM gin_metapage_info(get_raw_page('test1_y_idx', 1)); ERROR: input page is not a GIN metapage DETAIL: Flags 0002, expected 0008 +SELECT * FROM gin_page_opaque_info(get_raw_page('test1', 0)); +ERROR: input page is not a valid GIN data leaf page +DETAIL: Special size 0, expected 8 SELECT * FROM gin_page_opaque_info(get_raw_page('test1_y_idx', 1)); -[ RECORD 1 ]--------- rightlink | 4294967295 maxoff | 0 flags | {leaf} +SELECT * FROM gin_leafpage_items(get_raw_page('test1', 0)); +ERROR: input page is not a valid GIN data leaf page +DETAIL: Special size 0, expected 8 SELECT * FROM gin_leafpage_items(get_raw_page('test1_y_idx', 1)); ERROR: input page is not a compressed GIN data leaf page DETAIL: Flags 0002, expected 0083 diff --git a/contrib/pageinspect/expected/gist.out b/contrib/pageinspect/expected/gist.out index 3f33e04066..d5fb5abb72 100644 --- a/contrib/pageinspect/expected/gist.out +++ b/contrib/pageinspect/expected/gist.out @@ -30,6 +30,11 @@ SELECT * FROM gist_page_opaque_info(get_raw_page('test_gist_idx', 2)); (1 row) COMMIT; +SELECT * FROM gist_page_opaque_info(get_raw_page('test_gist', 0)); +ERROR: input page is not a valid gist page +DETAIL: Special size 0, expected 16 +SELECT * FROM gist_page_items(get_raw_page('test_gist', 0), 'test_gist'); +ERROR: "test_gist" is not an index SELECT * FROM gist_page_items(get_raw_page('test_gist_idx', 0), 'test_gist_idx'); itemoffset | ctid | itemlen | dead | keys ------------+-----------+---------+------+------------------- @@ -53,6 +58,9 @@ SELECT * FROM gist_page_items(get_raw_page('test_gist_idx', 1), 'test_gist_idx') -- gist_page_items_bytea prints the raw key data as a bytea. The output of that is -- platform-dependent (endianness), so omit the actual key data from the output. +SELECT itemoffset, ctid, itemlen FROM gist_page_items_bytea(get_raw_page('test_gist', 0)); +ERROR: input page is not a valid gist page +DETAIL: Special size 0, expected 16 SELECT itemoffset, ctid, itemlen FROM gist_page_items_bytea(get_raw_page('test_gist_idx', 0)); itemoffset | ctid | itemlen ------------+-----------+--------- @@ -68,6 +76,9 @@ SELECT itemoffset, ctid, itemlen FROM gist_page_items_bytea(get_raw_page('test_g CREATE INDEX test_gist_btree on test_gist(t); SELECT gist_page_items(get_raw_page('test_gist_btree', 0), 'test_gist_btree'); ERROR: "test_gist_btree" is not a GiST index +SELECT gist_page_items_bytea(get_raw_page('test_gist_btree', 0)); +ERROR: input page is not a valid gist page +DETAIL: page id 0, expected 65409 -- Failure with incorrect page size -- Suppress the DETAIL message, to allow the tests to work across various -- page sizes. diff --git a/contrib/pageinspect/expected/hash.out b/contrib/pageinspect/expected/hash.out index 6c606630dd..566a5e27e5 100644 --- a/contrib/pageinspect/expected/hash.out +++ b/contrib/pageinspect/expected/hash.out @@ -2,6 +2,8 @@ CREATE TABLE test_hash (a int, b text); INSERT INTO test_hash VALUES (1, 'one'); CREATE INDEX test_hash_a_idx ON test_hash USING hash (a); \x +SELECT hash_page_type(get_raw_page('test_hash', 0)); +ERROR: index table contains corrupted page SELECT hash_page_type(get_raw_page('test_hash_a_idx', 0)); -[ RECORD 1 ]--+--------- hash_page_type | metapage @@ -28,6 +30,8 @@ hash_page_type | bitmap SELECT hash_page_type(get_raw_page('test_hash_a_idx', 6)); ERROR: block number 6 is out of range for relation "test_hash_a_idx" +SELECT * FROM hash_bitmap_info('test_hash', 0); +ERROR: "test_hash" is not an index SELECT * FROM hash_bitmap_info('test_hash_a_idx', -1); ERROR: invalid block number SELECT * FROM hash_bitmap_info('test_hash_a_idx', 0); @@ -46,6 +50,10 @@ SELECT * FROM hash_bitmap_info('test_hash_a_idx', 6); ERROR: block number 6 is out of range for relation "test_hash_a_idx" SELECT magic, version, ntuples, bsize, bmsize, bmshift, maxbucket, highmask, lowmask, ovflpoint, firstfree, nmaps, procid, spares, mapp FROM +hash_metapage_info(get_raw_page('test_hash', 0)); +ERROR: index table contains corrupted page +SELECT magic, version, ntuples, bsize, bmsize, bmshift, maxbucket, highmask, +lowmask, ovflpoint, firstfree, nmaps, procid, spares, mapp FROM hash_metapage_info(get_raw_page('test_hash_a_idx', 0)); -[ RECORD 1 ]-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- magic | 105121344 @@ -86,6 +94,10 @@ hash_metapage_info(get_raw_page('test_hash_a_idx', 5)); ERROR: page is not a hash meta page SELECT live_items, dead_items, page_size, hasho_prevblkno, hasho_nextblkno, hasho_bucket, hasho_flag, hasho_page_id FROM +hash_page_stats(get_raw_page('test_hash', 0)); +ERROR: index table contains corrupted page +SELECT live_items, dead_items, page_size, hasho_prevblkno, hasho_nextblkno, +hasho_bucket, hasho_flag, hasho_page_id FROM hash_page_stats(get_raw_page('test_hash_a_idx', 0)); ERROR: page is not a hash bucket or overflow page SELECT live_items, dead_items, page_size, hasho_prevblkno, hasho_nextblkno, @@ -144,6 +156,8 @@ SELECT live_items, dead_items, page_size, hasho_prevblkno, hasho_nextblkno, hasho_bucket, hasho_flag, hasho_page_id FROM hash_page_stats(get_raw_page('test_hash_a_idx', 5)); ERROR: page is not a hash bucket or overflow page +SELECT * FROM hash_page_items(get_raw_page('test_hash', 0)); +ERROR: index table contains corrupted page SELECT * FROM hash_page_items(get_raw_page('test_hash_a_idx', 0)); ERROR: page is not a hash bucket or overflow page SELECT * FROM hash_page_items(get_raw_page('test_hash_a_idx', 1)); diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c index f55128857e..6a3a485571 100644 --- a/contrib/pageinspect/ginfuncs.c +++ b/contrib/pageinspect/ginfuncs.c @@ -49,6 +49,14 @@ gin_metapage_info(PG_FUNCTION_ARGS) page = get_page_from_raw(raw_page); + if (PageGetSpecialSize(page) != MAXALIGN(sizeof(GinPageOpaqueData))) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("input page is not a valid GIN metapage"), + errdetail("Special size %d, expected %d", + (int) PageGetSpecialSize(page), + (int) MAXALIGN(sizeof(GinPageOpaqueData))))); + opaq = (GinPageOpaque) PageGetSpecialPointer(page); if (opaq->flags != GIN_META) ereport(ERROR, @@ -107,6 +115,14 @@ gin_page_opaque_info(PG_FUNCTION_ARGS) page = get_page_from_raw(raw_page); + if (PageGetSpecialSize(page) != MAXALIGN(sizeof(GinPageOpaqueData))) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("input page is not a valid GIN data leaf page"), + errdetail("Special size %d, expected %d", + (int) PageGetSpecialSize(page), + (int) MAXALIGN(sizeof(GinPageOpaqueData))))); + opaq = (GinPageOpaque) PageGetSpecialPointer(page); /* Build a tuple descriptor for our result type */ diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c index a31cff47fe..05e58a2ab2 100644 --- a/contrib/pageinspect/gistfuncs.c +++ b/contrib/pageinspect/gistfuncs.c @@ -55,7 +55,23 @@ gist_page_opaque_info(PG_FUNCTION_ARGS) page = get_page_from_raw(raw_page); + /* verify the special space has the expected size */ + if (PageGetSpecialSize(page) != sizeof(GISTPageOpaqueData)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("input page is not a valid gist page"), + errdetail("Special size %d, expected %d", + (int) PageGetSpecialSize(page), + (int) MAXALIGN(sizeof(GISTPageOpaqueData))))); + opaq = (GISTPageOpaque) PageGetSpecialPointer(page); + if (opaq->gist_page_id != GIST_PAGE_ID) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("input page is not a valid gist page"), + errdetail("page id %d, expected %d", + opaq->gist_page_id, + GIST_PAGE_ID))); /* Build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) @@ -101,6 +117,7 @@ gist_page_items_bytea(PG_FUNCTION_ARGS) bytea *raw_page = PG_GETARG_BYTEA_P(0); ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; Page page; + GISTPageOpaque opaq; OffsetNumber offset; OffsetNumber maxoff = InvalidOffsetNumber; @@ -113,6 +130,24 @@ gist_page_items_bytea(PG_FUNCTION_ARGS) page = get_page_from_raw(raw_page); + /* verify the special space has the expected size */ + if (PageGetSpecialSize(page) != sizeof(GISTPageOpaqueData)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("input page is not a valid gist page"), + errdetail("Special size %d, expected %d", + (int) PageGetSpecialSize(page), + (int) MAXALIGN(sizeof(GISTPageOpaqueData))))); + + opaq = (GISTPageOpaque) PageGetSpecialPointer(page); + if (opaq->gist_page_id != GIST_PAGE_ID) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("input page is not a valid gist page"), + errdetail("page id %d, expected %d", + opaq->gist_page_id, + GIST_PAGE_ID))); + /* Avoid bogus PageGetMaxOffsetNumber() call with deleted pages */ if (GistPageIsDeleted(page)) elog(NOTICE, "page is deleted"); diff --git a/contrib/pageinspect/sql/brin.sql b/contrib/pageinspect/sql/brin.sql index 8717229c5d..9b9641ff61 100644 --- a/contrib/pageinspect/sql/brin.sql +++ b/contrib/pageinspect/sql/brin.sql @@ -2,16 +2,21 @@ CREATE TABLE test1 (a int, b text); INSERT INTO test1 VALUES (1, 'one'); CREATE INDEX test1_a_idx ON test1 USING brin (a); +SELECT brin_page_type(get_raw_page('test1', 0)); SELECT brin_page_type(get_raw_page('test1_a_idx', 0)); SELECT brin_page_type(get_raw_page('test1_a_idx', 1)); SELECT brin_page_type(get_raw_page('test1_a_idx', 2)); +SELECT * FROM brin_metapage_info(get_raw_page('test1', 0)); SELECT * FROM brin_metapage_info(get_raw_page('test1_a_idx', 0)); SELECT * FROM brin_metapage_info(get_raw_page('test1_a_idx', 1)); +SELECT * FROM brin_revmap_data(get_raw_page('test1', 0)); SELECT * FROM brin_revmap_data(get_raw_page('test1_a_idx', 0)) LIMIT 5; SELECT * FROM brin_revmap_data(get_raw_page('test1_a_idx', 1)) LIMIT 5; +SELECT * FROM brin_page_items(get_raw_page('test1', 0), 'test1') + ORDER BY blknum, attnum LIMIT 5; SELECT * FROM brin_page_items(get_raw_page('test1_a_idx', 2), 'test1_a_idx') ORDER BY blknum, attnum LIMIT 5; diff --git a/contrib/pageinspect/sql/btree.sql b/contrib/pageinspect/sql/btree.sql index fdda777b9e..de7a59e3dc 100644 --- a/contrib/pageinspect/sql/btree.sql +++ b/contrib/pageinspect/sql/btree.sql @@ -1,21 +1,25 @@ -CREATE TABLE test1 (a int8, b text); -INSERT INTO test1 VALUES (72057594037927937, 'text'); +CREATE TABLE test1 (a int8, b int4range); +INSERT INTO test1 VALUES (72057594037927937, '[0,1)'); CREATE INDEX test1_a_idx ON test1 USING btree (a); \x +SELECT * FROM bt_metap('test1'); SELECT * FROM bt_metap('test1_a_idx'); +SELECT * FROM bt_page_stats('test1', 0); SELECT * FROM bt_page_stats('test1_a_idx', -1); SELECT * FROM bt_page_stats('test1_a_idx', 0); SELECT * FROM bt_page_stats('test1_a_idx', 1); SELECT * FROM bt_page_stats('test1_a_idx', 2); +SELECT * FROM bt_page_items('test1', 0); SELECT * FROM bt_page_items('test1_a_idx', -1); SELECT * FROM bt_page_items('test1_a_idx', 0); SELECT * FROM bt_page_items('test1_a_idx', 1); SELECT * FROM bt_page_items('test1_a_idx', 2); +SELECT * FROM bt_page_items(get_raw_page('test1', 0)); SELECT * FROM bt_page_items(get_raw_page('test1_a_idx', -1)); SELECT * FROM bt_page_items(get_raw_page('test1_a_idx', 0)); SELECT * FROM bt_page_items(get_raw_page('test1_a_idx', 1)); @@ -26,6 +30,11 @@ CREATE INDEX test1_a_hash ON test1 USING hash(a); SELECT bt_metap('test1_a_hash'); SELECT bt_page_stats('test1_a_hash', 0); SELECT bt_page_items('test1_a_hash', 0); +SELECT bt_page_items(get_raw_page('test1_a_hash', 0)); +CREATE INDEX test1_b_gist ON test1 USING gist(b); +SELECT bt_page_items(get_raw_page('test1_b_gist', 0)); +CREATE INDEX test1_a_brin ON test1 USING brin(a); +SELECT bt_page_items(get_raw_page('test1_a_brin', 0)); -- Failure with incorrect page size -- Suppress the DETAIL message, to allow the tests to work across various diff --git a/contrib/pageinspect/sql/gin.sql b/contrib/pageinspect/sql/gin.sql index aadb07856d..fb27c70f3e 100644 --- a/contrib/pageinspect/sql/gin.sql +++ b/contrib/pageinspect/sql/gin.sql @@ -4,11 +4,14 @@ CREATE INDEX test1_y_idx ON test1 USING gin (y) WITH (fastupdate = off); \x +SELECT * FROM gin_metapage_info(get_raw_page('test1', 0)); SELECT * FROM gin_metapage_info(get_raw_page('test1_y_idx', 0)); SELECT * FROM gin_metapage_info(get_raw_page('test1_y_idx', 1)); +SELECT * FROM gin_page_opaque_info(get_raw_page('test1', 0)); SELECT * FROM gin_page_opaque_info(get_raw_page('test1_y_idx', 1)); +SELECT * FROM gin_leafpage_items(get_raw_page('test1', 0)); SELECT * FROM gin_leafpage_items(get_raw_page('test1_y_idx', 1)); INSERT INTO test1 SELECT x, ARRAY[1,10] FROM generate_series(2,10000) x; diff --git a/contrib/pageinspect/sql/gist.sql b/contrib/pageinspect/sql/gist.sql index 8abeb19140..ea7d0e0796 100644 --- a/contrib/pageinspect/sql/gist.sql +++ b/contrib/pageinspect/sql/gist.sql @@ -18,17 +18,21 @@ SELECT * FROM gist_page_opaque_info(get_raw_page('test_gist_idx', 1)); SELECT * FROM gist_page_opaque_info(get_raw_page('test_gist_idx', 2)); COMMIT; +SELECT * FROM gist_page_opaque_info(get_raw_page('test_gist', 0)); +SELECT * FROM gist_page_items(get_raw_page('test_gist', 0), 'test_gist'); SELECT * FROM gist_page_items(get_raw_page('test_gist_idx', 0), 'test_gist_idx'); SELECT * FROM gist_page_items(get_raw_page('test_gist_idx', 1), 'test_gist_idx') LIMIT 5; -- gist_page_items_bytea prints the raw key data as a bytea. The output of that is -- platform-dependent (endianness), so omit the actual key data from the output. +SELECT itemoffset, ctid, itemlen FROM gist_page_items_bytea(get_raw_page('test_gist', 0)); SELECT itemoffset, ctid, itemlen FROM gist_page_items_bytea(get_raw_page('test_gist_idx', 0)); -- Failure with non-GiST index. CREATE INDEX test_gist_btree on test_gist(t); SELECT gist_page_items(get_raw_page('test_gist_btree', 0), 'test_gist_btree'); +SELECT gist_page_items_bytea(get_raw_page('test_gist_btree', 0)); -- Failure with incorrect page size -- Suppress the DETAIL message, to allow the tests to work across various diff --git a/contrib/pageinspect/sql/hash.sql b/contrib/pageinspect/sql/hash.sql index fcddd706ae..8a27bf77bf 100644 --- a/contrib/pageinspect/sql/hash.sql +++ b/contrib/pageinspect/sql/hash.sql @@ -4,6 +4,7 @@ CREATE INDEX test_hash_a_idx ON test_hash USING hash (a); \x +SELECT hash_page_type(get_raw_page('test_hash', 0)); SELECT hash_page_type(get_raw_page('test_hash_a_idx', 0)); SELECT hash_page_type(get_raw_page('test_hash_a_idx', 1)); SELECT hash_page_type(get_raw_page('test_hash_a_idx', 2)); @@ -13,6 +14,7 @@ SELECT hash_page_type(get_raw_page('test_hash_a_idx', 5)); SELECT hash_page_type(get_raw_page('test_hash_a_idx', 6)); +SELECT * FROM hash_bitmap_info('test_hash', 0); SELECT * FROM hash_bitmap_info('test_hash_a_idx', -1); SELECT * FROM hash_bitmap_info('test_hash_a_idx', 0); SELECT * FROM hash_bitmap_info('test_hash_a_idx', 1); @@ -23,6 +25,10 @@ SELECT * FROM hash_bitmap_info('test_hash_a_idx', 5); SELECT * FROM hash_bitmap_info('test_hash_a_idx', 6); +SELECT magic, version, ntuples, bsize, bmsize, bmshift, maxbucket, highmask, +lowmask, ovflpoint, firstfree, nmaps, procid, spares, mapp FROM +hash_metapage_info(get_raw_page('test_hash', 0)); + SELECT magic, version, ntuples, bsize, bmsize, bmshift, maxbucket, highmask, lowmask, ovflpoint, firstfree, nmaps, procid, spares, mapp FROM hash_metapage_info(get_raw_page('test_hash_a_idx', 0)); @@ -47,6 +53,10 @@ SELECT magic, version, ntuples, bsize, bmsize, bmshift, maxbucket, highmask, lowmask, ovflpoint, firstfree, nmaps, procid, spares, mapp FROM hash_metapage_info(get_raw_page('test_hash_a_idx', 5)); +SELECT live_items, dead_items, page_size, hasho_prevblkno, hasho_nextblkno, +hasho_bucket, hasho_flag, hasho_page_id FROM +hash_page_stats(get_raw_page('test_hash', 0)); + SELECT live_items, dead_items, page_size, hasho_prevblkno, hasho_nextblkno, hasho_bucket, hasho_flag, hasho_page_id FROM hash_page_stats(get_raw_page('test_hash_a_idx', 0)); @@ -71,6 +81,7 @@ SELECT live_items, dead_items, page_size, hasho_prevblkno, hasho_nextblkno, hasho_bucket, hasho_flag, hasho_page_id FROM hash_page_stats(get_raw_page('test_hash_a_idx', 5)); +SELECT * FROM hash_page_items(get_raw_page('test_hash', 0)); SELECT * FROM hash_page_items(get_raw_page('test_hash_a_idx', 0)); SELECT * FROM hash_page_items(get_raw_page('test_hash_a_idx', 1)); SELECT * FROM hash_page_items(get_raw_page('test_hash_a_idx', 2)); -- 2.35.0