diff --git a/contrib/pageinspect/brinfuncs.c b/contrib/pageinspect/brinfuncs.c index ca9ece64d2..4faccd3074 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 %s page", "BRIN"), + errdetail("Expected special size %d, got %d.", + (int) MAXALIGN(sizeof(BrinSpecialSpace)), + (int) PageGetSpecialSize(page)))); + 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) != MAXALIGN(sizeof(BrinSpecialSpace))) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("input page is not a valid %s page", "BRIN"), + errdetail("Expected special size %d, got %d.", + (int) MAXALIGN(sizeof(BrinSpecialSpace)), + (int) PageGetSpecialSize(page)))); + /* 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..7651c59bbf 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 %s page", "btree"), + errdetail("Expected special size %d, got %d.", + (int) MAXALIGN(sizeof(BTPageOpaqueData)), + (int) PageGetSpecialSize(uargs->page)))); + opaque = (BTPageOpaque) PageGetSpecialPointer(uargs->page); if (P_ISMETA(opaque)) @@ -620,6 +629,11 @@ 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_INVALID_PARAMETER_VALUE), + errmsg("block is not a valid btree leaf page"))); + if (P_ISDELETED(opaque)) elog(NOTICE, "page is deleted"); diff --git a/contrib/pageinspect/expected/brin.out b/contrib/pageinspect/expected/brin.out index 10cd36c177..62ee783b60 100644 --- a/contrib/pageinspect/expected/brin.out +++ b/contrib/pageinspect/expected/brin.out @@ -52,4 +52,14 @@ SELECT * FROM brin_page_items(get_raw_page('test1_a_idx', 2), 'test1_a_idx') CREATE INDEX test1_a_btree ON test1 (a); SELECT brin_page_items(get_raw_page('test1_a_btree', 0), 'test1_a_btree'); ERROR: "test1_a_btree" is not a BRIN index +-- Mask DETAIL messages as these are not portable across architectures. +\set VERBOSITY terse +-- Invalid special area size +SELECT brin_page_type(get_raw_page('test1', 0)); +ERROR: input page is not a valid BRIN page +SELECT * FROM brin_metapage_info(get_raw_page('test1', 0)); +ERROR: input page is not a valid BRIN page +SELECT * FROM brin_revmap_data(get_raw_page('test1', 0)); +ERROR: input page is not a valid BRIN page +\set VERBOSITY default DROP TABLE test1; diff --git a/contrib/pageinspect/expected/btree.out b/contrib/pageinspect/expected/btree.out index 80b3dfe861..89d2160990 100644 --- a/contrib/pageinspect/expected/btree.out +++ b/contrib/pageinspect/expected/btree.out @@ -1,5 +1,5 @@ -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_a_idx'); @@ -78,11 +78,25 @@ 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 --- Failure with incorrect page size +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); +-- Special area of GiST is the same as btree, this complains about inconsistent +-- leaf data on the page. +SELECT bt_page_items(get_raw_page('test1_b_gist', 0)); +ERROR: block is not a valid btree leaf page +-- Several failure modes. -- Suppress the DETAIL message, to allow the tests to work across various --- page sizes. +-- page sizes and architectures. \set VERBOSITY terse +-- invalid page size SELECT bt_page_items('aaa'::bytea); ERROR: invalid page size +-- invalid special area size +CREATE INDEX test1_a_brin ON test1 USING brin(a); +SELECT bt_page_items(get_raw_page('test1', 0)); +ERROR: input page is not a valid btree page +SELECT bt_page_items(get_raw_page('test1_a_brin', 0)); +ERROR: input page is not a valid btree page \set VERBOSITY default DROP TABLE test1; diff --git a/contrib/pageinspect/expected/gin.out b/contrib/pageinspect/expected/gin.out index 802f48284b..e9fdb4cf20 100644 --- a/contrib/pageinspect/expected/gin.out +++ b/contrib/pageinspect/expected/gin.out @@ -35,15 +35,23 @@ FROM gin_leafpage_items(get_raw_page('test1_y_idx', -[ RECORD 1 ] ?column? | t -DROP TABLE test1; --- Failure with incorrect page size +-- Failure with various modes. -- Suppress the DETAIL message, to allow the tests to work across various --- page sizes. +-- page sizes and architectures. \set VERBOSITY terse +-- invalid page size SELECT gin_leafpage_items('aaa'::bytea); ERROR: invalid page size SELECT gin_metapage_info('bbb'::bytea); ERROR: invalid page size SELECT gin_page_opaque_info('ccc'::bytea); ERROR: invalid page size +-- invalid special area size +SELECT * FROM gin_metapage_info(get_raw_page('test1', 0)); +ERROR: input page is not a valid GIN metapage +SELECT * FROM gin_page_opaque_info(get_raw_page('test1', 0)); +ERROR: input page is not a valid GIN data leaf page +SELECT * FROM gin_leafpage_items(get_raw_page('test1', 0)); +ERROR: input page is not a valid GIN data leaf page \set VERBOSITY default +DROP TABLE test1; diff --git a/contrib/pageinspect/expected/gist.out b/contrib/pageinspect/expected/gist.out index 73154029ca..3161d1decd 100644 --- a/contrib/pageinspect/expected/gist.out +++ b/contrib/pageinspect/expected/gist.out @@ -70,15 +70,23 @@ 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 --- Failure with incorrect page size +-- Failure with various modes. -- Suppress the DETAIL message, to allow the tests to work across various --- page sizes. +-- page sizes and architectures. \set VERBOSITY terse +-- invalid page size SELECT gist_page_items_bytea('aaa'::bytea); ERROR: invalid page size SELECT gist_page_items('aaa'::bytea, 'test_gist_idx'::regclass); ERROR: invalid page size SELECT gist_page_opaque_info('aaa'::bytea); ERROR: invalid page size +-- invalid special area size +SELECT * FROM gist_page_opaque_info(get_raw_page('test_gist', 0)); +ERROR: input page is not a valid GiST page +SELECT gist_page_items_bytea(get_raw_page('test_gist', 0)); +ERROR: input page is not a valid GiST page +SELECT gist_page_items_bytea(get_raw_page('test_gist_btree', 0)); +ERROR: input page is not a valid GiST page \set VERBOSITY default DROP TABLE test_gist; diff --git a/contrib/pageinspect/expected/hash.out b/contrib/pageinspect/expected/hash.out index 6c606630dd..96c9511457 100644 --- a/contrib/pageinspect/expected/hash.out +++ b/contrib/pageinspect/expected/hash.out @@ -167,10 +167,11 @@ ERROR: page is not a hash bucket or overflow page CREATE INDEX test_hash_a_btree ON test_hash USING btree (a); SELECT hash_bitmap_info('test_hash_a_btree', 0); ERROR: "test_hash_a_btree" is not a hash index --- Failure with incorrect page size +-- Failure with various modes. -- Suppress the DETAIL message, to allow the tests to work across various --- page sizes. +-- page sizes and architectures. \set VERBOSITY terse +-- invalid page size SELECT hash_metapage_info('aaa'::bytea); ERROR: invalid page size SELECT hash_page_items('bbb'::bytea); @@ -179,5 +180,14 @@ SELECT hash_page_stats('ccc'::bytea); ERROR: invalid page size SELECT hash_page_type('ddd'::bytea); ERROR: invalid page size +-- invalid special area size +SELECT hash_metapage_info(get_raw_page('test_hash', 0)); +ERROR: input page is not a valid hash page +SELECT hash_page_items(get_raw_page('test_hash', 0)); +ERROR: input page is not a valid hash page +SELECT hash_page_stats(get_raw_page('test_hash', 0)); +ERROR: input page is not a valid hash page +SELECT hash_page_type(get_raw_page('test_hash', 0)); +ERROR: input page is not a valid hash page \set VERBOSITY default DROP TABLE test_hash; diff --git a/contrib/pageinspect/ginfuncs.c b/contrib/pageinspect/ginfuncs.c index e425cbcdb8..b0fa6a079f 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("Expected special size %d, got %d.", + (int) MAXALIGN(sizeof(GinPageOpaqueData)), + (int) PageGetSpecialSize(page)))); + 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("Expected special size %d, got %d.", + (int) MAXALIGN(sizeof(GinPageOpaqueData)), + (int) PageGetSpecialSize(page)))); + opaq = (GinPageOpaque) PageGetSpecialPointer(page); /* Build a tuple descriptor for our result type */ @@ -188,9 +204,9 @@ gin_leafpage_items(PG_FUNCTION_ARGS) 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))))); + errdetail("Expected special size %d, got %d.", + (int) MAXALIGN(sizeof(GinPageOpaqueData)), + (int) PageGetSpecialSize(page)))); opaq = (GinPageOpaque) PageGetSpecialPointer(page); if (opaq->flags != (GIN_DATA | GIN_LEAF | GIN_COMPRESSED)) diff --git a/contrib/pageinspect/gistfuncs.c b/contrib/pageinspect/gistfuncs.c index f7e6bf81d4..be2ee8433a 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) != MAXALIGN(sizeof(GISTPageOpaqueData))) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("input page is not a valid %s page", "GiST"), + errdetail("Expected special size %d, got %d.", + (int) MAXALIGN(sizeof(GISTPageOpaqueData)), + (int) PageGetSpecialSize(page)))); + 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 %s page", "GiST"), + errdetail("Expected %08x, got %08x.", + GIST_PAGE_ID, + opaq->gist_page_id))); /* Build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) @@ -105,6 +121,7 @@ gist_page_items_bytea(PG_FUNCTION_ARGS) Tuplestorestate *tupstore; MemoryContext oldcontext; Page page; + GISTPageOpaque opaq; OffsetNumber offset; OffsetNumber maxoff = InvalidOffsetNumber; @@ -139,6 +156,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) != MAXALIGN(sizeof(GISTPageOpaqueData))) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("input page is not a valid %s page", "GiST"), + errdetail("Expected special size %d, got %d.", + (int) MAXALIGN(sizeof(GISTPageOpaqueData)), + (int) PageGetSpecialSize(page)))); + + 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 %s page", "GiST"), + errdetail("Expected %08x, got %08x.", + GIST_PAGE_ID, + opaq->gist_page_id))); + /* Avoid bogus PageGetMaxOffsetNumber() call with deleted pages */ if (GistPageIsDeleted(page)) elog(NOTICE, "page is deleted"); diff --git a/contrib/pageinspect/hashfuncs.c b/contrib/pageinspect/hashfuncs.c index 7ea7fb5662..db9dd7ebae 100644 --- a/contrib/pageinspect/hashfuncs.c +++ b/contrib/pageinspect/hashfuncs.c @@ -66,14 +66,17 @@ verify_hash_page(bytea *raw_page, int flags) if (PageGetSpecialSize(page) != MAXALIGN(sizeof(HashPageOpaqueData))) ereport(ERROR, - (errcode(ERRCODE_INDEX_CORRUPTED), - errmsg("index table contains corrupted page"))); + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("input page is not a valid %s page", "hash"), + errdetail("Expected special size %d, got %d.", + (int) MAXALIGN(sizeof(HashPageOpaqueData)), + (int) PageGetSpecialSize(page)))); pageopaque = (HashPageOpaque) PageGetSpecialPointer(page); if (pageopaque->hasho_page_id != HASHO_PAGE_ID) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("page is not a hash page"), + errmsg("input page is not a valid %s page", "hash"), errdetail("Expected %08x, got %08x.", HASHO_PAGE_ID, pageopaque->hasho_page_id))); @@ -134,7 +137,7 @@ verify_hash_page(bytea *raw_page, int flags) ereport(ERROR, (errcode(ERRCODE_INDEX_CORRUPTED), errmsg("invalid version for metadata"), - errdetail("Expected %d, got %d", + errdetail("Expected %d, got %d.", HASH_VERSION, metap->hashm_version))); } diff --git a/contrib/pageinspect/sql/brin.sql b/contrib/pageinspect/sql/brin.sql index 8717229c5d..dc5d1661b6 100644 --- a/contrib/pageinspect/sql/brin.sql +++ b/contrib/pageinspect/sql/brin.sql @@ -19,4 +19,12 @@ SELECT * FROM brin_page_items(get_raw_page('test1_a_idx', 2), 'test1_a_idx') CREATE INDEX test1_a_btree ON test1 (a); SELECT brin_page_items(get_raw_page('test1_a_btree', 0), 'test1_a_btree'); +-- Mask DETAIL messages as these are not portable across architectures. +\set VERBOSITY terse +-- Invalid special area size +SELECT brin_page_type(get_raw_page('test1', 0)); +SELECT * FROM brin_metapage_info(get_raw_page('test1', 0)); +SELECT * FROM brin_revmap_data(get_raw_page('test1', 0)); +\set VERBOSITY default + DROP TABLE test1; diff --git a/contrib/pageinspect/sql/btree.sql b/contrib/pageinspect/sql/btree.sql index fdda777b9e..44d83f90ba 100644 --- a/contrib/pageinspect/sql/btree.sql +++ b/contrib/pageinspect/sql/btree.sql @@ -1,5 +1,5 @@ -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 @@ -26,12 +26,22 @@ 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); +-- Special area of GiST is the same as btree, this complains about inconsistent +-- leaf data on the page. +SELECT bt_page_items(get_raw_page('test1_b_gist', 0)); --- Failure with incorrect page size +-- Several failure modes. -- Suppress the DETAIL message, to allow the tests to work across various --- page sizes. +-- page sizes and architectures. \set VERBOSITY terse +-- invalid page size SELECT bt_page_items('aaa'::bytea); +-- invalid special area size +CREATE INDEX test1_a_brin ON test1 USING brin(a); +SELECT bt_page_items(get_raw_page('test1', 0)); +SELECT bt_page_items(get_raw_page('test1_a_brin', 0)); \set VERBOSITY default DROP TABLE test1; diff --git a/contrib/pageinspect/sql/gin.sql b/contrib/pageinspect/sql/gin.sql index aadb07856d..6499b5c72b 100644 --- a/contrib/pageinspect/sql/gin.sql +++ b/contrib/pageinspect/sql/gin.sql @@ -18,13 +18,18 @@ FROM gin_leafpage_items(get_raw_page('test1_y_idx', (pg_relation_size('test1_y_idx') / current_setting('block_size')::bigint)::int - 1)); -DROP TABLE test1; - --- Failure with incorrect page size +-- Failure with various modes. -- Suppress the DETAIL message, to allow the tests to work across various --- page sizes. +-- page sizes and architectures. \set VERBOSITY terse +-- invalid page size SELECT gin_leafpage_items('aaa'::bytea); SELECT gin_metapage_info('bbb'::bytea); SELECT gin_page_opaque_info('ccc'::bytea); +-- invalid special area size +SELECT * FROM gin_metapage_info(get_raw_page('test1', 0)); +SELECT * FROM gin_page_opaque_info(get_raw_page('test1', 0)); +SELECT * FROM gin_leafpage_items(get_raw_page('test1', 0)); \set VERBOSITY default + +DROP TABLE test1; diff --git a/contrib/pageinspect/sql/gist.sql b/contrib/pageinspect/sql/gist.sql index 0d3eed9a19..58f4c35d1d 100644 --- a/contrib/pageinspect/sql/gist.sql +++ b/contrib/pageinspect/sql/gist.sql @@ -30,13 +30,18 @@ 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'); --- Failure with incorrect page size +-- Failure with various modes. -- Suppress the DETAIL message, to allow the tests to work across various --- page sizes. +-- page sizes and architectures. \set VERBOSITY terse +-- invalid page size SELECT gist_page_items_bytea('aaa'::bytea); SELECT gist_page_items('aaa'::bytea, 'test_gist_idx'::regclass); SELECT gist_page_opaque_info('aaa'::bytea); +-- invalid special area size +SELECT * FROM gist_page_opaque_info(get_raw_page('test_gist', 0)); +SELECT gist_page_items_bytea(get_raw_page('test_gist', 0)); +SELECT gist_page_items_bytea(get_raw_page('test_gist_btree', 0)); \set VERBOSITY default DROP TABLE test_gist; diff --git a/contrib/pageinspect/sql/hash.sql b/contrib/pageinspect/sql/hash.sql index fcddd706ae..ccc984c086 100644 --- a/contrib/pageinspect/sql/hash.sql +++ b/contrib/pageinspect/sql/hash.sql @@ -82,14 +82,20 @@ SELECT * FROM hash_page_items(get_raw_page('test_hash_a_idx', 5)); CREATE INDEX test_hash_a_btree ON test_hash USING btree (a); SELECT hash_bitmap_info('test_hash_a_btree', 0); --- Failure with incorrect page size +-- Failure with various modes. -- Suppress the DETAIL message, to allow the tests to work across various --- page sizes. +-- page sizes and architectures. \set VERBOSITY terse +-- invalid page size SELECT hash_metapage_info('aaa'::bytea); SELECT hash_page_items('bbb'::bytea); SELECT hash_page_stats('ccc'::bytea); SELECT hash_page_type('ddd'::bytea); +-- invalid special area size +SELECT hash_metapage_info(get_raw_page('test_hash', 0)); +SELECT hash_page_items(get_raw_page('test_hash', 0)); +SELECT hash_page_stats(get_raw_page('test_hash', 0)); +SELECT hash_page_type(get_raw_page('test_hash', 0)); \set VERBOSITY default DROP TABLE test_hash;