postgres.git / summary / log / commit / refs

commit    63979e5bea14c533dadc8f44cee0ec7a2899ccf5
Author:   Nathan Bossart <nathan@postgresql.org>
Date:     Fri Aug 21 16:50:39 2026 +0000

    Ensure TOAST storage parameters have unsettable defaults.
    
    A follow-up commit will teach autovacuum and manual VACUUM to fill
    in a TOAST table's unset storage parameters from its main table's.
    To be able to determine whether a parameter is set, it must default
    to a value that users cannot set.  Of all the parameters that can
    be set on TOAST tables, log_autovacuum_min_duration is the only one
    that violates this rule.  This commit changes its default to -2 so
    that we can tell whether it is set.  This shouldn't produce any
    user-visible behavior changes.
    
    While at it, add assertions to ensure all storage parameters that
    can be set on TOAST tables continue to follow this rule.
    
    Reviewed-by: Michael Paquier <michael@paquier.xyz>
    Reviewed-by: Sami Imseih <samimseih@gmail.com>
    Reviewed-by: Greg Burd <greg@burd.me>
    Tested-by: solai v <solai.cdac@gmail.com>
    Discussion: https://postgr.es/m/aFRxC1W_kZU9OjJ9%40nathan


src/backend/access/common/reloptions.c | 76 +++++++++++++++++++++++++++++++++- src/backend/postmaster/autovacuum.c | 2 +- 2 files changed, 76 insertions(+), 2 deletions(-) diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c index fab8294e732..7ad9a7b9a3b 100644 --- a/src/backend/access/common/reloptions.c +++ b/src/backend/access/common/reloptions.c @@ -348,7 +348,7 @@ static relopt_int intRelOpts[] = RELOPT_KIND_HEAP | RELOPT_KIND_TOAST, ShareUpdateExclusiveLock }, - -1, -1, INT_MAX + -2, -1, INT_MAX }, { { @@ -613,6 +613,76 @@ static void parse_one_reloption(relopt_value *option, char *text_str, ((option).isset ? strlen((option).string_val) : \ ((relopt_string *) (option).gen)->default_len) +#ifdef USE_ASSERT_CHECKING +/* + * Verify that every option a TOAST table accepts defaults to a value the user + * cannot set. That way, we can tell whether a reloption is set on the TOAST + * table or if we should pull the value from its main table. + */ +static void +assert_toast_defaults_unsettable(void) +{ + for (int i = 0; relOpts[i]; i++) + { + relopt_gen *gen = relOpts[i]; + + if ((gen->kinds & RELOPT_KIND_TOAST) == 0) + continue; + + /* + * A TOAST table's value is filled in from its main table's at the + * same offset in the same struct, so the option must be settable on a + * heap too. + */ + Assert((gen->kinds & RELOPT_KIND_HEAP) != 0); + + switch (gen->type) + { + case RELOPT_TYPE_TERNARY: + + /* + * Ternaries carry no default, and parse_one_reloption() can + * only produce true or false, so PG_TERNARY_UNSET is already + * beyond a user's reach. + */ + break; + + case RELOPT_TYPE_INT: + { + relopt_int *optint = (relopt_int *) gen; + + Assert(optint->default_val < optint->min || + optint->default_val > optint->max); + break; + } + + case RELOPT_TYPE_REAL: + { + relopt_real *optreal = (relopt_real *) gen; + + Assert(optreal->default_val < optreal->min || + optreal->default_val > optreal->max); + break; + } + + case RELOPT_TYPE_ENUM: + { + relopt_enum *optenum = (relopt_enum *) gen; + + for (relopt_enum_elt_def *elt = optenum->members; + elt->string_val; elt++) + Assert(elt->symbol_val != optenum->default_val); + break; + } + + default: + /* Neither bools nor strings can express "unset". */ + Assert(false); + } + } +} +#endif /* USE_ASSERT_CHECKING */ + /* * initialize_reloptions * initialization routine, must be called before parsing @@ -730,6 +800,10 @@ initialize_reloptions(void) /* flag the work is complete */ need_initialization = false; + +#ifdef USE_ASSERT_CHECKING + assert_toast_defaults_unsettable(); +#endif } /* diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index 0aa5056918f..9c73c10fb11 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -2836,7 +2836,7 @@ table_recheck_autovac(Oid relid, HTAB *table_toast_map, * defaults, autovacuum's own first and plain vacuum second. */ - /* -1 in autovac setting means use log_autovacuum_min_duration */ + /* a negative setting means use log_autovacuum_min_duration */ log_vacuum_min_duration = (avopts && avopts->log_vacuum_min_duration >= 0) ? avopts->log_vacuum_min_duration : Log_autovacuum_min_duration;