From 34fcd735f1ebd5efba8653cdbfbfd076b081660a Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Fri, 11 Sep 2026 10:54:48 +0900 Subject: [PATCH] Add support for TOAST chunk_id type in binary upgrades This commit adds a new SQL function able to set the type of a chunk_id attribute for a TOAST table across binary upgrades. The value is set when the creation of a TOAST table is required across upgrades, in the same fashion as the TOAST relation's oid and relfilenode. Note that this piece currently works only with a TOAST table's chunk_id set at OIDOID, because it is currently the only type of on-disk external TOAST pointer supported. This change is required for a follow-up feature that aims to introduce support for 8-byte OIDs in external TOAST pointers. Taking care of this issue separately is less code churn for the next changes, and perhaps some of the surrounding discussions with support for different types of external on-disk TOAST pointers will find this new facility useful. Bump catalog version. Author: Michael Paquier Reviewed-by: Greg Burd Reviewed-by: Bharath Rupireddy Reviewed-by: Yugo Nagata Discussion: https://postgr.es/m/af19kUjwjhaoUTLn@paquier.xyz --- src/backend/catalog/heap.c | 1 + src/backend/catalog/toasting.c | 20 ++++++++++++++++++- src/backend/utils/adt/pg_upgrade_support.c | 11 ++++++++++ src/bin/pg_dump/pg_dump.c | 14 ++++++++++--- src/include/catalog/binary_upgrade.h | 1 + src/include/catalog/catversion.h | 2 +- src/include/catalog/pg_proc.dat | 5 +++++ .../expected/spgist_name_ops.out | 6 ++++-- 8 files changed, 53 insertions(+), 7 deletions(-) diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index a107193d7ab..1c188b7a0ff 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -80,6 +80,7 @@ /* Potentially set by pg_upgrade_support functions */ Oid binary_upgrade_next_heap_pg_class_oid = InvalidOid; Oid binary_upgrade_next_toast_pg_class_oid = InvalidOid; +Oid binary_upgrade_next_toast_chunk_id_typoid = InvalidOid; RelFileNumber binary_upgrade_next_heap_pg_class_relfilenumber = InvalidRelFileNumber; RelFileNumber binary_upgrade_next_toast_pg_class_relfilenumber = InvalidRelFileNumber; diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c index 4aa52a4bd25..b19478ba072 100644 --- a/src/backend/catalog/toasting.c +++ b/src/backend/catalog/toasting.c @@ -146,6 +146,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, int16 coloptions[2]; ObjectAddress baseobject, toastobject; + Oid toast_chunkid_typid = OIDOID; /* * Is it already toasted? @@ -184,6 +185,23 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, */ if (!OidIsValid(binary_upgrade_next_toast_pg_class_oid)) return false; + + /* + * The attribute type for chunk_id should have been set when + * requesting a TOAST table creation. + */ + if (!OidIsValid(binary_upgrade_next_toast_chunk_id_typoid)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("toast chunk_id type not set while in binary upgrade mode"))); + if (binary_upgrade_next_toast_chunk_id_typoid != OIDOID) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("cannot support toast chunk_id type %u in binary upgrade mode", + binary_upgrade_next_toast_chunk_id_typoid))); + + toast_chunkid_typid = binary_upgrade_next_toast_chunk_id_typoid; + binary_upgrade_next_toast_chunk_id_typoid = InvalidOid; } /* @@ -205,7 +223,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, tupdesc = CreateTemplateTupleDesc(3); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "chunk_id", - OIDOID, + toast_chunkid_typid, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "chunk_seq", diff --git a/src/backend/utils/adt/pg_upgrade_support.c b/src/backend/utils/adt/pg_upgrade_support.c index 760991f1adc..f5017022d2e 100644 --- a/src/backend/utils/adt/pg_upgrade_support.c +++ b/src/backend/utils/adt/pg_upgrade_support.c @@ -149,6 +149,17 @@ binary_upgrade_set_next_toast_pg_class_oid(PG_FUNCTION_ARGS) PG_RETURN_VOID(); } +Datum +binary_upgrade_set_next_toast_chunk_id_typoid(PG_FUNCTION_ARGS) +{ + Oid typoid = PG_GETARG_OID(0); + + CHECK_IS_BINARY_UPGRADE; + binary_upgrade_next_toast_chunk_id_typoid = typoid; + + PG_RETURN_VOID(); +} + Datum binary_upgrade_set_next_toast_relfilenode(PG_FUNCTION_ARGS) { diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 7a12e03ca02..388c3b9c346 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -104,6 +104,7 @@ typedef struct RelFileNumber relfilenumber; /* object filenode */ Oid toast_oid; /* toast table OID */ RelFileNumber toast_relfilenumber; /* toast table filenode */ + Oid toast_chunk_id_typoid; /* type of chunk_id attribute */ Oid toast_index_oid; /* toast table index OID */ RelFileNumber toast_index_relfilenumber; /* toast table index filenode */ } BinaryUpgradeClassOidItem; @@ -5869,7 +5870,10 @@ collectBinaryUpgradeClassOids(Archive *fout) const char *query; query = "SELECT c.oid, c.relkind, c.relfilenode, c.reltoastrelid, " - "ct.relfilenode, i.indexrelid, cti.relfilenode " + "ct.relfilenode, i.indexrelid, cti.relfilenode, " + "(SELECT a.atttypid FROM pg_attribute AS a " + " WHERE a.attrelid = c.reltoastrelid AND attname = 'chunk_id'::text) " + " AS toastchunktypid " "FROM pg_catalog.pg_class c LEFT JOIN pg_catalog.pg_index i " "ON (c.reltoastrelid = i.indrelid AND i.indisvalid) " "LEFT JOIN pg_catalog.pg_class ct ON (c.reltoastrelid = ct.oid) " @@ -5891,6 +5895,7 @@ collectBinaryUpgradeClassOids(Archive *fout) binaryUpgradeClassOids[i].toast_relfilenumber = atooid(PQgetvalue(res, i, 4)); binaryUpgradeClassOids[i].toast_index_oid = atooid(PQgetvalue(res, i, 5)); binaryUpgradeClassOids[i].toast_index_relfilenumber = atooid(PQgetvalue(res, i, 6)); + binaryUpgradeClassOids[i].toast_chunk_id_typoid = atooid(PQgetvalue(res, i, 7)); } PQclear(res); @@ -5907,7 +5912,7 @@ binary_upgrade_set_pg_class_oids(Archive *fout, /* * Preserve the OID and relfilenumber of the table, table's index, table's - * toast table and toast table's index if any. + * toast table, toast table's chunk type and toast table's index if any. * * One complexity is that the current table definition might not require * the creation of a TOAST table, but the old database might have a TOAST @@ -5922,7 +5927,7 @@ binary_upgrade_set_pg_class_oids(Archive *fout, BinaryUpgradeClassOidItemCmp); appendPQExpBufferStr(upgrade_buffer, - "\n-- For binary upgrade, must preserve pg_class oids and relfilenodes\n"); + "\n-- For binary upgrade, must preserve pg_class oids, toast chunk type oids and relfilenodes\n"); if (entry->relkind != RELKIND_INDEX && entry->relkind != RELKIND_PARTITIONED_INDEX) @@ -5955,6 +5960,9 @@ binary_upgrade_set_pg_class_oids(Archive *fout, appendPQExpBuffer(upgrade_buffer, "SELECT pg_catalog.binary_upgrade_set_next_toast_relfilenode('%u'::pg_catalog.oid);\n", entry->toast_relfilenumber); + appendPQExpBuffer(upgrade_buffer, + "SELECT pg_catalog.binary_upgrade_set_next_toast_chunk_id_typoid('%u'::pg_catalog.oid);\n", + entry->toast_chunk_id_typoid); /* every toast table has an index */ appendPQExpBuffer(upgrade_buffer, diff --git a/src/include/catalog/binary_upgrade.h b/src/include/catalog/binary_upgrade.h index 7bf7ae44385..117f3e3f774 100644 --- a/src/include/catalog/binary_upgrade.h +++ b/src/include/catalog/binary_upgrade.h @@ -29,6 +29,7 @@ extern PGDLLIMPORT Oid binary_upgrade_next_index_pg_class_oid; extern PGDLLIMPORT RelFileNumber binary_upgrade_next_index_pg_class_relfilenumber; extern PGDLLIMPORT Oid binary_upgrade_next_toast_pg_class_oid; extern PGDLLIMPORT RelFileNumber binary_upgrade_next_toast_pg_class_relfilenumber; +extern PGDLLIMPORT Oid binary_upgrade_next_toast_chunk_id_typoid; extern PGDLLIMPORT Oid binary_upgrade_next_pg_enum_oid; extern PGDLLIMPORT Oid binary_upgrade_next_pg_authid_oid; diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index f8aaf9aab02..12ae8f4331a 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -57,6 +57,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 202609102 +#define CATALOG_VERSION_NO 202609111 #endif diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index c53ce68c717..74d386b868b 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -11992,6 +11992,11 @@ proname => 'binary_upgrade_set_next_toast_pg_class_oid', provolatile => 'v', proparallel => 'r', prorettype => 'void', proargtypes => 'oid', prosrc => 'binary_upgrade_set_next_toast_pg_class_oid' }, +{ oid => '8219', descr => 'for use by pg_upgrade', + proname => 'binary_upgrade_set_next_toast_chunk_id_typoid', + provolatile => 'v', proparallel => 'r', prorettype => 'void', + proargtypes => 'oid', + prosrc => 'binary_upgrade_set_next_toast_chunk_id_typoid' }, { oid => '3589', descr => 'for use by pg_upgrade', proname => 'binary_upgrade_set_next_pg_enum_oid', provolatile => 'v', proparallel => 'r', prorettype => 'void', proargtypes => 'oid', diff --git a/src/test/modules/spgist_name_ops/expected/spgist_name_ops.out b/src/test/modules/spgist_name_ops/expected/spgist_name_ops.out index 1ee65ede243..35e59d0cd83 100644 --- a/src/test/modules/spgist_name_ops/expected/spgist_name_ops.out +++ b/src/test/modules/spgist_name_ops/expected/spgist_name_ops.out @@ -61,9 +61,10 @@ select * from t binary_upgrade_set_next_pg_enum_oid | | binary_upgrade_set_next_pg_enum_oid binary_upgrade_set_next_pg_tablespace_oid | | binary_upgrade_set_next_pg_tablespace_oid binary_upgrade_set_next_pg_type_oid | | binary_upgrade_set_next_pg_type_oid + binary_upgrade_set_next_toast_chunk_id_typoid | | binary_upgrade_set_next_toast_chunk_id_typoid binary_upgrade_set_next_toast_pg_class_oid | 1 | binary_upgrade_set_next_toast_pg_class_oid binary_upgrade_set_next_toast_relfilenode | | binary_upgrade_set_next_toast_relfilenode -(13 rows) +(14 rows) -- Verify clean failure when INCLUDE'd columns result in overlength tuple -- The error message details are platform-dependent, so show only SQLSTATE @@ -110,9 +111,10 @@ select * from t binary_upgrade_set_next_pg_enum_oid | | binary_upgrade_set_next_pg_enum_oid binary_upgrade_set_next_pg_tablespace_oid | | binary_upgrade_set_next_pg_tablespace_oid binary_upgrade_set_next_pg_type_oid | | binary_upgrade_set_next_pg_type_oid + binary_upgrade_set_next_toast_chunk_id_typoid | | binary_upgrade_set_next_toast_chunk_id_typoid binary_upgrade_set_next_toast_pg_class_oid | 1 | binary_upgrade_set_next_toast_pg_class_oid binary_upgrade_set_next_toast_relfilenode | | binary_upgrade_set_next_toast_relfilenode -(13 rows) +(14 rows) \set VERBOSITY sqlstate insert into t values(repeat('xyzzy', 12), 42, repeat('xyzzy', 4000));