From e1da067a047e4724194868ac9cdd141caabe8314 Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Thu, 10 Sep 2026 16:08:50 +0900 Subject: [PATCH v16 2/8] Add relation option toast_value_type This relation option gives the possibility to define the attribute type that can be used for chunk_id in a TOAST table when it is created initially. This parameter has no effect if a TOAST table exists, even after it is modified later on, even on rewrites. This can be set only to "oid" currently, and will be expanded with a second mode later. Note: perhaps it would make sense to introduce that only when support for 8-byte OID values are added to TOAST, the split is here to ease review. --- src/include/utils/rel.h | 17 ++++++++++++++++ src/backend/access/common/reloptions.c | 21 +++++++++++++++++++ src/backend/catalog/toasting.c | 16 +++++++++++++++ src/bin/psql/tab-complete.in.c | 1 + src/test/regress/expected/reloptions.out | 22 ++++++++++++++++++++ src/test/regress/sql/reloptions.sql | 12 +++++++++++ doc/src/sgml/ref/create_table.sgml | 26 ++++++++++++++++++++++++ 7 files changed, 115 insertions(+) diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 41ab4586c6b5..029d614b6f23 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -341,11 +341,20 @@ typedef enum StdRdOptIndexCleanup STDRD_OPTION_VACUUM_INDEX_CLEANUP_NOT_SET, } StdRdOptIndexCleanup; +/* StdRdOptions->toast_value_type values */ +typedef enum StdRdOptToastValueType +{ + STDRD_OPTION_TOAST_VALUE_TYPE_INVALID = 0, + STDRD_OPTION_TOAST_VALUE_TYPE_OID, +} StdRdOptToastValueType; + typedef struct StdRdOptions { int32 vl_len_; /* varlena header (do not touch directly!) */ int fillfactor; /* page fill factor in percent (0..100) */ int toast_tuple_target; /* target for tuple toasting */ + StdRdOptToastValueType toast_value_type; /* type assigned to chunk_id + * at toast table creation */ AutoVacOpts autovacuum; /* autovacuum-related options */ bool user_catalog_table; /* use as an additional catalog relation */ int parallel_workers; /* max number of parallel workers */ @@ -370,6 +379,14 @@ typedef struct StdRdOptions ((relation)->rd_options ? \ ((StdRdOptions *) (relation)->rd_options)->toast_tuple_target : (defaulttarg)) +/* + * RelationGetToastValueType + * Returns the relation's toast_value_type. Note multiple eval of argument! + */ +#define RelationGetToastValueType(relation, defaulttarg) \ + ((relation)->rd_options ? \ + ((StdRdOptions *) (relation)->rd_options)->toast_value_type : (defaulttarg)) + /* * RelationGetFillFactor * Returns the relation's fillfactor. Note multiple eval of argument! diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index c3f6f45f4609..82491a31a9a4 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -548,6 +548,14 @@ static relopt_enum_elt_def viewCheckOptValues[] = {(const char *) NULL} /* list terminator */ }; +/* values from StdRdOptToastValueType */ +static relopt_enum_elt_def StdRdOptToastValueTypes[] = +{ + /* no value for INVALID */ + {"oid", STDRD_OPTION_TOAST_VALUE_TYPE_OID}, + {(const char *) NULL} /* list terminator */ +}; + static relopt_enum enumRelOpts[] = { { @@ -561,6 +569,17 @@ static relopt_enum enumRelOpts[] = STDRD_OPTION_VACUUM_INDEX_CLEANUP_NOT_SET, gettext_noop("Valid values are \"on\", \"off\", and \"auto\".") }, + { + { + "toast_value_type", + "Controls the attribute type of chunk_id at toast table creation", + RELOPT_KIND_HEAP, + ShareUpdateExclusiveLock + }, + StdRdOptToastValueTypes, + STDRD_OPTION_TOAST_VALUE_TYPE_OID, + gettext_noop("Valid values are \"oid\".") + }, { { "buffering", @@ -2078,6 +2097,8 @@ static const relopt_parse_elt stdRdOptionsTab[] = { offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, log_analyze_min_duration)}, {"toast_tuple_target", RELOPT_TYPE_INT, offsetof(StdRdOptions, toast_tuple_target)}, + {"toast_value_type", RELOPT_TYPE_ENUM, + offsetof(StdRdOptions, toast_value_type)}, {"autovacuum_vacuum_cost_delay", RELOPT_TYPE_REAL, offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_delay)}, {"autovacuum_vacuum_scale_factor", RELOPT_TYPE_REAL, diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c index bc0a72268335..c3f70fcd8ab1 100644 --- a/src/backend/catalog/toasting.c +++ b/src/backend/catalog/toasting.c @@ -159,9 +159,25 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, */ if (!IsBinaryUpgrade) { + StdRdOptToastValueType value_type; + /* Normal mode, normal check */ if (!needs_toast_table(rel)) return false; + + value_type = RelationGetToastValueType(rel, STDRD_OPTION_TOAST_VALUE_TYPE_OID); + + /* no default clause to catch new values added */ + switch (value_type) + { + case STDRD_OPTION_TOAST_VALUE_TYPE_OID: + toast_chunkid_typid = OIDOID; + break; + case STDRD_OPTION_TOAST_VALUE_TYPE_INVALID: + elog(ERROR, "unexpected toast_value_type value %d", + value_type); + break; + } } else { diff --git a/src/bin/psql/tab-complete.in.c b/src/bin/psql/tab-complete.in.c index 8e1a1d69740c..84a129efff54 100644 --- a/src/bin/psql/tab-complete.in.c +++ b/src/bin/psql/tab-complete.in.c @@ -1441,6 +1441,7 @@ static const char *const table_storage_parameters[] = { "toast.vacuum_max_eager_freeze_failure_rate", "toast.vacuum_truncate", "toast_tuple_target", + "toast_value_type", "user_catalog_table", "vacuum_index_cleanup", "vacuum_max_eager_freeze_failure_rate", diff --git a/src/test/regress/expected/reloptions.out b/src/test/regress/expected/reloptions.out index e3a974f26112..9b4c8587aa49 100644 --- a/src/test/regress/expected/reloptions.out +++ b/src/test/regress/expected/reloptions.out @@ -194,6 +194,28 @@ SELECT reloptions FROM pg_class WHERE oid = :toast_oid; -- Fail on non-existent options in toast namespace CREATE TABLE reloptions_test2 (i int) WITH (toast.not_existing_option = 42); ERROR: unrecognized parameter "not_existing_option" +-- Test toast_value_type. +CREATE TABLE reloptions_test2 (s VARCHAR) WITH (toast.toast_value_type = 'oid'); +ERROR: unrecognized parameter "toast_value_type" +CREATE TABLE reloptions_test2 (s VARCHAR) WITH (toast_value_type = 'int8'); +ERROR: invalid value for enum option "toast_value_type": int8 +DETAIL: Valid values are "oid". +CREATE TABLE reloptions_test2 (s VARCHAR) WITH (toast_value_type = 'oid'); +SELECT reloptions FROM pg_class WHERE oid = 'reloptions_test2'::regclass; + reloptions +------------------------ + {toast_value_type=oid} +(1 row) + +DROP TABLE reloptions_test2; +-- relkinds not supported. +CREATE INDEX reloptions_test_idx0 ON reloptions_test (s) + WITH (toast_value_type = 'oid'); +ERROR: unrecognized parameter "toast_value_type" +CREATE TABLE reloptions_test2 (i int) PARTITION BY RANGE (i) + WITH (toast_value_type = 'oid'); +ERROR: cannot specify storage parameters for a partitioned table +HINT: Specify storage parameters for its leaf partitions instead. -- Mix TOAST & heap DROP TABLE reloptions_test; CREATE TABLE reloptions_test (s VARCHAR) WITH diff --git a/src/test/regress/sql/reloptions.sql b/src/test/regress/sql/reloptions.sql index 680c8bf86148..503d15d16e51 100644 --- a/src/test/regress/sql/reloptions.sql +++ b/src/test/regress/sql/reloptions.sql @@ -112,6 +112,18 @@ SELECT reloptions FROM pg_class WHERE oid = :toast_oid; -- Fail on non-existent options in toast namespace CREATE TABLE reloptions_test2 (i int) WITH (toast.not_existing_option = 42); +-- Test toast_value_type. +CREATE TABLE reloptions_test2 (s VARCHAR) WITH (toast.toast_value_type = 'oid'); +CREATE TABLE reloptions_test2 (s VARCHAR) WITH (toast_value_type = 'int8'); +CREATE TABLE reloptions_test2 (s VARCHAR) WITH (toast_value_type = 'oid'); +SELECT reloptions FROM pg_class WHERE oid = 'reloptions_test2'::regclass; +DROP TABLE reloptions_test2; +-- relkinds not supported. +CREATE INDEX reloptions_test_idx0 ON reloptions_test (s) + WITH (toast_value_type = 'oid'); +CREATE TABLE reloptions_test2 (i int) PARTITION BY RANGE (i) + WITH (toast_value_type = 'oid'); + -- Mix TOAST & heap DROP TABLE reloptions_test; diff --git a/doc/src/sgml/ref/create_table.sgml b/doc/src/sgml/ref/create_table.sgml index e342585c7f08..79622c1a23d6 100644 --- a/doc/src/sgml/ref/create_table.sgml +++ b/doc/src/sgml/ref/create_table.sgml @@ -1653,6 +1653,32 @@ WITH ( MODULUS numeric_literal, REM + + toast_value_type (enum) + + toast_value_type storage parameter + + + + + Specifies the attribute type of chunk_id to use when + creating a TOAST relation for this table. The + default is oid. + This parameter cannot be set for TOAST tables. + + + The value is only consulted when the TOAST relation + is created. Changing it afterwards has no effect on an existing + TOAST relation, and a table rewrite such as + CLUSTER or + VACUUM FULL + preserves the type already in use. A dump and restore, on the other + hand, recreates the TOAST relation and therefore + applies the current value of this parameter. + + + + parallel_workers (integer) -- 2.55.0