pageinspect: Improve page_header() for pages of 32kB
authorMichael Paquier <[email protected]>
Mon, 12 Jul 2021 02:05:27 +0000 (11:05 +0900)
committerMichael Paquier <[email protected]>
Mon, 12 Jul 2021 02:05:27 +0000 (11:05 +0900)
ld_upper, ld_lower, pd_special and the page size have been using
smallint as return type, which could cause those fields to return
negative values in certain cases for builds configures with a page size
of 32kB.

Bump pageinspect to 1.10.  page_header() is able to handle the correct
return type of those fields at runtime when using an older version of
the extension, with some tests are added to cover that.

Author: Quan Zongliang
Reviewed-by: Michael Paquier, Bharath Rupireddy
Discussion: https://postgr.es/m/8b8ec36e-61fe-14f9-005d-07bc85aa4eed@yeah.net

contrib/pageinspect/Makefile
contrib/pageinspect/expected/oldextversions.out
contrib/pageinspect/pageinspect--1.9--1.10.sql [new file with mode: 0644]
contrib/pageinspect/pageinspect.control
contrib/pageinspect/rawpage.c
contrib/pageinspect/sql/oldextversions.sql

index 2d330ddb2857d241533c3ab5395ef76d4bf7b954..5c0736564abdcf712da8b7f89068eaa5232720d5 100644 (file)
@@ -13,7 +13,7 @@ OBJS = \
    rawpage.o
 
 EXTENSION = pageinspect
-DATA =  pageinspect--1.8--1.9.sql \
+DATA =  pageinspect--1.9--1.10.sql pageinspect--1.8--1.9.sql \
    pageinspect--1.7--1.8.sql pageinspect--1.6--1.7.sql \
    pageinspect--1.5.sql pageinspect--1.5--1.6.sql \
    pageinspect--1.4--1.5.sql pageinspect--1.3--1.4.sql \
index 04dc7f8640eba14e34d43cfd00d93c0f5067382f..f5c4b61bd793fc6f96fc670a23777a81d3ca98a1 100644 (file)
@@ -36,5 +36,21 @@ SELECT * FROM bt_page_items('test1_a_idx', 1);
           1 | (0,1) |      16 | f     | f    | 01 00 00 00 00 00 00 01 | f    | (0,1) | 
 (1 row)
 
+-- page_header() uses int instead of smallint for lower, upper, special and
+-- pagesize in pageinspect >= 1.10.
+ALTER EXTENSION pageinspect UPDATE TO '1.9';
+\df page_header
+                                                                                                                  List of functions
+ Schema |    Name     | Result data type |                                                                                         Argument data types                                                                                         | Type 
+--------+-------------+------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------
+ public | page_header | record           | page bytea, OUT lsn pg_lsn, OUT checksum smallint, OUT flags smallint, OUT lower smallint, OUT upper smallint, OUT special smallint, OUT pagesize smallint, OUT version smallint, OUT prune_xid xid | func
+(1 row)
+
+SELECT pagesize, version FROM page_header(get_raw_page('test1', 0));
+ pagesize | version 
+----------+---------
+     8192 |       4
+(1 row)
+
 DROP TABLE test1;
 DROP EXTENSION pageinspect;
diff --git a/contrib/pageinspect/pageinspect--1.9--1.10.sql b/contrib/pageinspect/pageinspect--1.9--1.10.sql
new file mode 100644 (file)
index 0000000..8dd9a27
--- /dev/null
@@ -0,0 +1,21 @@
+/* contrib/pageinspect/pageinspect--1.9--1.10.sql */
+
+-- complain if script is sourced in psql, rather than via ALTER EXTENSION
+\echo Use "ALTER EXTENSION pageinspect UPDATE TO '1.10'" to load this file. \quit
+
+--
+-- page_header()
+--
+DROP FUNCTION page_header(IN page bytea);
+CREATE FUNCTION page_header(IN page bytea,
+    OUT lsn pg_lsn,
+    OUT checksum smallint,
+    OUT flags smallint,
+    OUT lower int,
+    OUT upper int,
+    OUT special int,
+    OUT pagesize int,
+    OUT version smallint,
+    OUT prune_xid xid)
+AS 'MODULE_PATHNAME', 'page_header'
+LANGUAGE C STRICT PARALLEL SAFE;
index bd716769a174c71dfc59aee2cc05208e5a3f3901..7cdf37913dae2cc497aabd5faab174a19ae9d832 100644 (file)
@@ -1,5 +1,5 @@
 # pageinspect extension
 comment = 'inspect the contents of database pages at a low level'
-default_version = '1.9'
+default_version = '1.10'
 module_pathname = '$libdir/pageinspect'
 relocatable = true
index e9fee73bc436f7588ea1fccf9c6275b3de0d1b89..4bfa346c24a2b6c60d440dadcdf115ae225666c8 100644 (file)
@@ -296,10 +296,33 @@ page_header(PG_FUNCTION_ARGS)
        values[0] = LSNGetDatum(lsn);
    values[1] = UInt16GetDatum(page->pd_checksum);
    values[2] = UInt16GetDatum(page->pd_flags);
-   values[3] = UInt16GetDatum(page->pd_lower);
-   values[4] = UInt16GetDatum(page->pd_upper);
-   values[5] = UInt16GetDatum(page->pd_special);
-   values[6] = UInt16GetDatum(PageGetPageSize(page));
+
+   /* pageinspect >= 1.10 uses int4 instead of int2 for those fields */
+   switch (TupleDescAttr(tupdesc, 3)->atttypid)
+   {
+       case INT2OID:
+           Assert(TupleDescAttr(tupdesc, 4)->atttypid == INT2OID &&
+                  TupleDescAttr(tupdesc, 5)->atttypid == INT2OID &&
+                  TupleDescAttr(tupdesc, 6)->atttypid == INT2OID);
+           values[3] = UInt16GetDatum(page->pd_lower);
+           values[4] = UInt16GetDatum(page->pd_upper);
+           values[5] = UInt16GetDatum(page->pd_special);
+           values[6] = UInt16GetDatum(PageGetPageSize(page));
+           break;
+       case INT4OID:
+           Assert(TupleDescAttr(tupdesc, 4)->atttypid == INT4OID &&
+                  TupleDescAttr(tupdesc, 5)->atttypid == INT4OID &&
+                  TupleDescAttr(tupdesc, 6)->atttypid == INT4OID);
+           values[3] = Int32GetDatum(page->pd_lower);
+           values[4] = Int32GetDatum(page->pd_upper);
+           values[5] = Int32GetDatum(page->pd_special);
+           values[6] = Int32GetDatum(PageGetPageSize(page));
+           break;
+       default:
+           elog(ERROR, "incorrect output types");
+           break;
+   }
+
    values[7] = UInt16GetDatum(PageGetPageLayoutVersion(page));
    values[8] = TransactionIdGetDatum(page->pd_prune_xid);
 
index 78e08f40e8247fc1d1a56d5ef68e93acd1f9c314..9f953492c23c3e85db36a9fbc827f66e6ee2e5a9 100644 (file)
@@ -16,5 +16,11 @@ SELECT page_checksum(get_raw_page('test1', 0), 0) IS NOT NULL AS silly_checksum_
 SELECT * FROM bt_page_stats('test1_a_idx', 1);
 SELECT * FROM bt_page_items('test1_a_idx', 1);
 
+-- page_header() uses int instead of smallint for lower, upper, special and
+-- pagesize in pageinspect >= 1.10.
+ALTER EXTENSION pageinspect UPDATE TO '1.9';
+\df page_header
+SELECT pagesize, version FROM page_header(get_raw_page('test1', 0));
+
 DROP TABLE test1;
 DROP EXTENSION pageinspect;