From 2a7688763f187d29db887db456695bf1da1d564d Mon Sep 17 00:00:00 2001 From: shihao zhong Date: Mon, 19 Oct 2026 23:57:54 -0400 Subject: [PATCH v1] Remove HEAP_HASOID_OLD Tuples with an oid field can no longer be created, and core code no longer reads this bit. Remove it, and remove the t_oid column from pageinspect's heap_page_items() and heap_page_item_attrs() in a new version 1.14. Discussion: https://postgr.es/m/CAApHDvqB=kapsgwvLiPZRhfyFcJB6nw-Xs2D-jHm6ddRcxP7zA@mail.gmail.com --- contrib/pageinspect/Makefile | 2 +- .../pageinspect/expected/oldextversions.out | 31 +++++++ contrib/pageinspect/expected/page.out | 3 +- contrib/pageinspect/heapfuncs.c | 43 ++++----- contrib/pageinspect/meson.build | 1 + .../pageinspect/pageinspect--1.13--1.14.sql | 93 +++++++++++++++++++ contrib/pageinspect/pageinspect.control | 2 +- contrib/pageinspect/sql/oldextversions.sql | 12 +++ doc/src/sgml/storage.sgml | 8 +- src/include/access/htup_details.h | 4 +- 10 files changed, 159 insertions(+), 40 deletions(-) create mode 100644 contrib/pageinspect/pageinspect--1.13--1.14.sql diff --git a/contrib/pageinspect/Makefile b/contrib/pageinspect/Makefile index eae989569d0..09774fd340c 100644 --- a/contrib/pageinspect/Makefile +++ b/contrib/pageinspect/Makefile @@ -13,7 +13,7 @@ OBJS = \ rawpage.o EXTENSION = pageinspect -DATA = pageinspect--1.12--1.13.sql \ +DATA = pageinspect--1.13--1.14.sql pageinspect--1.12--1.13.sql \ pageinspect--1.11--1.12.sql pageinspect--1.10--1.11.sql \ pageinspect--1.9--1.10.sql pageinspect--1.8--1.9.sql \ pageinspect--1.7--1.8.sql pageinspect--1.6--1.7.sql \ diff --git a/contrib/pageinspect/expected/oldextversions.out b/contrib/pageinspect/expected/oldextversions.out index 2910891ece7..5cd8fbc955b 100644 --- a/contrib/pageinspect/expected/oldextversions.out +++ b/contrib/pageinspect/expected/oldextversions.out @@ -66,5 +66,36 @@ SELECT * FROM brin_page_items(get_raw_page('test_1_a_brin_idx', 2), 'test_1_a_br 1 | 0 | 1 | f | f | f | f | {72057594037927937 .. 72057594037927937} (1 row) +-- heap_page_items() lost its t_oid column in 1.14, make sure we detect +-- an old function definition +ALTER EXTENSION pageinspect UPDATE TO '1.13'; +INSERT INTO test1 VALUES (1, 'x'), (2, 'y'); +DELETE FROM test1 WHERE a = 1; +VACUUM test1; +SELECT lp, lp_flags, t_oid, t_data FROM heap_page_items(get_raw_page('test1', 0)); + lp | lp_flags | t_oid | t_data +----+----------+-------+------------------------------ + 1 | 1 | | \x01000000000000010b74657874 + 2 | 0 | | + 3 | 1 | | \x02000000000000000579 +(3 rows) + +SELECT lp, t_oid, t_attrs FROM heap_page_item_attrs(get_raw_page('test1', 0), 'test1'); + lp | t_oid | t_attrs +----+-------+----------------------------------------- + 1 | | {"\\x0100000000000001","\\x0b74657874"} + 2 | | + 3 | | {"\\x0200000000000000","\\x0579"} +(3 rows) + +ALTER EXTENSION pageinspect UPDATE TO '1.14'; +SELECT lp, t_data FROM heap_page_items(get_raw_page('test1', 0)); + lp | t_data +----+------------------------------ + 1 | \x01000000000000010b74657874 + 2 | + 3 | \x02000000000000000579 +(3 rows) + DROP TABLE test1; DROP EXTENSION pageinspect; diff --git a/contrib/pageinspect/expected/page.out b/contrib/pageinspect/expected/page.out index fcf19c5ca5a..167d3175d31 100644 --- a/contrib/pageinspect/expected/page.out +++ b/contrib/pageinspect/expected/page.out @@ -134,7 +134,6 @@ SELECT unnest(raw_flags) HEAP_COMBOCID HEAP_HASEXTERNAL HEAP_HASNULL - HEAP_HASOID_OLD HEAP_HASVARWIDTH HEAP_HOT_UPDATED HEAP_KEYS_UPDATED @@ -150,7 +149,7 @@ SELECT unnest(raw_flags) HEAP_XMAX_LOCK_ONLY HEAP_XMIN_COMMITTED HEAP_XMIN_INVALID -(19 rows) +(18 rows) SELECT unnest(combined_flags) FROM heap_tuple_infomask_flags(x'FFFF'::int, x'FFFF'::int) ORDER BY 1; diff --git a/contrib/pageinspect/heapfuncs.c b/contrib/pageinspect/heapfuncs.c index 7be4770dc84..eb3f16c0ad1 100644 --- a/contrib/pageinspect/heapfuncs.c +++ b/contrib/pageinspect/heapfuncs.c @@ -38,21 +38,6 @@ #include "utils/builtins.h" #include "utils/rel.h" -/* - * It's not supported to create tuples with oids anymore, but when pg_upgrade - * was used to upgrade from an older version, tuples might still have an - * oid. Seems worthwhile to display that. - */ -static inline Oid -HeapTupleHeaderGetOidOld(const HeapTupleHeaderData *tup) -{ - if (tup->t_infomask & HEAP_HASOID_OLD) - return *((const Oid *) ((const char *) (tup) + (tup)->t_hoff - sizeof(Oid))); - else - return InvalidOid; -} - - /* * bits_to_text * @@ -231,7 +216,7 @@ heap_page_items(PG_FUNCTION_ARGS) int tuple_data_len; bytea *tuple_data_bytea; - /* Copy null bitmask and OID, if present */ + /* Copy null bitmask, if present */ if (tuphdr->t_infomask & HEAP_HASNULL) { int bitmaplen; @@ -248,11 +233,6 @@ heap_page_items(PG_FUNCTION_ARGS) else nulls[11] = true; - if (tuphdr->t_infomask & HEAP_HASOID_OLD) - values[12] = ObjectIdGetDatum(HeapTupleHeaderGetOidOld(tuphdr)); - else - nulls[12] = true; - /* Copy raw tuple data into bytea attribute */ tuple_data_len = lp_len - tuphdr->t_hoff; tuple_data_bytea = (bytea *) palloc(tuple_data_len + VARHDRSZ); @@ -261,13 +241,12 @@ heap_page_items(PG_FUNCTION_ARGS) memcpy(VARDATA(tuple_data_bytea), (char *) tuphdr + tuphdr->t_hoff, tuple_data_len); - values[13] = PointerGetDatum(tuple_data_bytea); + values[12] = PointerGetDatum(tuple_data_bytea); } else { nulls[11] = true; nulls[12] = true; - nulls[13] = true; } } else @@ -278,10 +257,24 @@ heap_page_items(PG_FUNCTION_ARGS) */ int i; - for (i = 4; i <= 13; i++) + for (i = 4; i <= 12; i++) nulls[i] = true; } + /* + * Before 1.14 column 13 was t_oid. It is always NULL now. 1.4 to + * 1.13 also have t_data after it. + */ + if (TupleDescAttr(inter_call_data->tupd, 12)->atttypid == OIDOID) + { + if (inter_call_data->tupd->natts == 14) + { + values[13] = values[12]; + nulls[13] = nulls[12]; + } + nulls[12] = true; + } + /* Build and return the result tuple. */ resultTuple = heap_form_tuple(inter_call_data->tupd, values, nulls); result = HeapTupleGetDatum(resultTuple); @@ -555,8 +548,6 @@ heap_tuple_infomask_flags(PG_FUNCTION_ARGS) flags[cnt++] = CStringGetTextDatum("HEAP_HASVARWIDTH"); if ((t_infomask & HEAP_HASEXTERNAL) != 0) flags[cnt++] = CStringGetTextDatum("HEAP_HASEXTERNAL"); - if ((t_infomask & HEAP_HASOID_OLD) != 0) - flags[cnt++] = CStringGetTextDatum("HEAP_HASOID_OLD"); if ((t_infomask & HEAP_XMAX_KEYSHR_LOCK) != 0) flags[cnt++] = CStringGetTextDatum("HEAP_XMAX_KEYSHR_LOCK"); if ((t_infomask & HEAP_COMBOCID) != 0) diff --git a/contrib/pageinspect/meson.build b/contrib/pageinspect/meson.build index c43ea400a4d..2f333635838 100644 --- a/contrib/pageinspect/meson.build +++ b/contrib/pageinspect/meson.build @@ -38,6 +38,7 @@ install_data( 'pageinspect--1.10--1.11.sql', 'pageinspect--1.11--1.12.sql', 'pageinspect--1.12--1.13.sql', + 'pageinspect--1.13--1.14.sql', 'pageinspect.control', kwargs: contrib_data_args, ) diff --git a/contrib/pageinspect/pageinspect--1.13--1.14.sql b/contrib/pageinspect/pageinspect--1.13--1.14.sql new file mode 100644 index 00000000000..01b1519f5a2 --- /dev/null +++ b/contrib/pageinspect/pageinspect--1.13--1.14.sql @@ -0,0 +1,93 @@ +/* contrib/pageinspect/pageinspect--1.13--1.14.sql */ + +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION pageinspect UPDATE TO '1.14'" to load this file. \quit + +-- Remove the t_oid column, tuples no longer have an oid field + +DROP FUNCTION heap_page_item_attrs(bytea, regclass); +DROP FUNCTION heap_page_item_attrs(bytea, regclass, bool); +DROP FUNCTION heap_page_items(bytea); + +CREATE FUNCTION heap_page_items(IN page bytea, + OUT lp smallint, + OUT lp_off smallint, + OUT lp_flags smallint, + OUT lp_len smallint, + OUT t_xmin xid, + OUT t_xmax xid, + OUT t_field3 int4, + OUT t_ctid tid, + OUT t_infomask2 integer, + OUT t_infomask integer, + OUT t_hoff smallint, + OUT t_bits text, + OUT t_data bytea) +RETURNS SETOF record +AS 'MODULE_PATHNAME', 'heap_page_items' +LANGUAGE C STRICT PARALLEL SAFE; + +CREATE FUNCTION heap_page_item_attrs( + IN page bytea, + IN rel_oid regclass, + IN do_detoast bool, + OUT lp smallint, + OUT lp_off smallint, + OUT lp_flags smallint, + OUT lp_len smallint, + OUT t_xmin xid, + OUT t_xmax xid, + OUT t_field3 int4, + OUT t_ctid tid, + OUT t_infomask2 integer, + OUT t_infomask integer, + OUT t_hoff smallint, + OUT t_bits text, + OUT t_attrs bytea[] + ) +RETURNS SETOF record +LANGUAGE SQL PARALLEL RESTRICTED +BEGIN ATOMIC +SELECT lp, + lp_off, + lp_flags, + lp_len, + t_xmin, + t_xmax, + t_field3, + t_ctid, + t_infomask2, + t_infomask, + t_hoff, + t_bits, + tuple_data_split( + rel_oid::oid, + t_data, + t_infomask, + t_infomask2, + t_bits, + do_detoast) + AS t_attrs + FROM heap_page_items(page); +END; + +CREATE FUNCTION heap_page_item_attrs(IN page bytea, IN rel_oid regclass, + OUT lp smallint, + OUT lp_off smallint, + OUT lp_flags smallint, + OUT lp_len smallint, + OUT t_xmin xid, + OUT t_xmax xid, + OUT t_field3 int4, + OUT t_ctid tid, + OUT t_infomask2 integer, + OUT t_infomask integer, + OUT t_hoff smallint, + OUT t_bits text, + OUT t_attrs bytea[] + ) +RETURNS SETOF record +LANGUAGE SQL PARALLEL RESTRICTED +BEGIN ATOMIC +SELECT * FROM heap_page_item_attrs(page, rel_oid, false); +END; diff --git a/contrib/pageinspect/pageinspect.control b/contrib/pageinspect/pageinspect.control index cfc87feac03..aee3f598a9e 100644 --- a/contrib/pageinspect/pageinspect.control +++ b/contrib/pageinspect/pageinspect.control @@ -1,5 +1,5 @@ # pageinspect extension comment = 'inspect the contents of database pages at a low level' -default_version = '1.13' +default_version = '1.14' module_pathname = '$libdir/pageinspect' relocatable = true diff --git a/contrib/pageinspect/sql/oldextversions.sql b/contrib/pageinspect/sql/oldextversions.sql index 44f564faec9..a250faf2f56 100644 --- a/contrib/pageinspect/sql/oldextversions.sql +++ b/contrib/pageinspect/sql/oldextversions.sql @@ -31,5 +31,17 @@ SELECT * FROM brin_page_items(get_raw_page('test_1_a_brin_idx', 2), 'test_1_a_br ALTER EXTENSION pageinspect UPDATE TO '1.12'; SELECT * FROM brin_page_items(get_raw_page('test_1_a_brin_idx', 2), 'test_1_a_brin_idx'); +-- heap_page_items() lost its t_oid column in 1.14, make sure we detect +-- an old function definition +ALTER EXTENSION pageinspect UPDATE TO '1.13'; +INSERT INTO test1 VALUES (1, 'x'), (2, 'y'); +DELETE FROM test1 WHERE a = 1; +VACUUM test1; +SELECT lp, lp_flags, t_oid, t_data FROM heap_page_items(get_raw_page('test1', 0)); +SELECT lp, t_oid, t_attrs FROM heap_page_item_attrs(get_raw_page('test1', 0), 'test1'); + +ALTER EXTENSION pageinspect UPDATE TO '1.14'; +SELECT lp, t_data FROM heap_page_items(get_raw_page('test1', 0)); + DROP TABLE test1; DROP EXTENSION pageinspect; diff --git a/doc/src/sgml/storage.sgml b/doc/src/sgml/storage.sgml index 83de016eaa5..397c0a39ea1 100644 --- a/doc/src/sgml/storage.sgml +++ b/doc/src/sgml/storage.sgml @@ -959,7 +959,7 @@ data. Empty in ordinary tables. All table rows are structured in the same way. There is a fixed-size header (occupying 23 bytes on most machines), followed by an optional null - bitmap, an optional object ID field, and the user data. The header is + bitmap and the user data. The header is detailed in . The actual user data (columns of the row) begins at the offset indicated by @@ -973,12 +973,6 @@ data. Empty in ordinary tables. t_infomask2). In this list of bits, a 1 bit indicates not-null, a 0 bit is a null. When the bitmap is not present, all columns are assumed not-null. - The object ID is only present if the HEAP_HASOID_OLD bit - is set in t_infomask. If present, it appears just - before the t_hoff boundary. Any padding needed to make - t_hoff a MAXALIGN multiple will appear between the null - bitmap and the object ID. (This in turn ensures that the object ID is - suitably aligned.) diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h index 77a6c48fd71..7d9c84a45ad 100644 --- a/src/include/access/htup_details.h +++ b/src/include/access/htup_details.h @@ -66,8 +66,6 @@ * fixed fields (HeapTupleHeaderData struct) * nulls bitmap (if HEAP_HASNULL is set in t_infomask) * alignment padding (as needed to make user data MAXALIGN'd) - * object ID (if HEAP_HASOID_OLD is set in t_infomask, not created - * anymore) * user data fields * * We store five "virtual" fields Xmin, Cmin, Xmax, Cmax, and Xvac in three @@ -190,7 +188,7 @@ struct HeapTupleHeaderData #define HEAP_HASNULL 0x0001 /* has null attribute(s) */ #define HEAP_HASVARWIDTH 0x0002 /* has variable-width attribute(s) */ #define HEAP_HASEXTERNAL 0x0004 /* has external stored attribute(s) */ -#define HEAP_HASOID_OLD 0x0008 /* has an object-id field */ +/* 0x0008 was HEAP_HASOID_OLD, don't reuse, pre-8.4 rows may have it */ #define HEAP_XMAX_KEYSHR_LOCK 0x0010 /* xmax is a key-shared locker */ #define HEAP_COMBOCID 0x0020 /* t_cid is a combo CID */ #define HEAP_XMAX_EXCL_LOCK 0x0040 /* xmax is exclusive locker */ -- 2.37.1 (Apple Git-137.1)